Repository navigation
datasource: Invoke, Lookup, DeclareOperations — call a connected source's declared operation through the host as the person #29
Description
What we are trying to do
A solution's Go backend calls one declared operation of a connected third-party API through the host, as the signed-in person, with one line: datasource.New(gw).Invoke(ctx, orgID, sourceID, "list_invoices", input). The host owns the credential, the route, the receipt and the audit row; the SDK carries the person's Work Context and the effect id, maps typed errors, and exposes receipt lookup. Nothing in this SDK ever sees a provider credential or URL.
Design: design/callable-sources.md (handbook branch rest-datasource, commit 26c2a93), rows S1, S3. The host method (DatasourceService.InvokeSourceOperation / LookupInvokeSourceOperation, DeclareSourceOperations, ListSourceOperations) is the saas-starter sibling's deliverable.
Sibling issues
Filled in by a comment below once every issue exists.
What is true today (saas-sdk-go main 9b9d219-era, verified 2026-10-09)
datasource/client.go— "the typed, gateway-bound client facade for the saas DatasourceService — the 'connection' half of datasource ingestion":Gatewayinterface (:36, the minimal surface from the solution runtime),Client{}overaccountsv1connect.DatasourceServiceClient,New(gw, opts...),AddGitHubSource,ListSources,Sync.datasource/types.goholds the ergonomic types.gen/saas/accounts/v1/is generated frommodule-saas-starter/module/services/accounts/protoat the ref inSOURCE.txt;README.md:113–127: "Never hand-editgen/or sed the module path"; the regen command is documented there; the SDK version tracks the saas-starter module version.- How a solution uses it:
obin-ai/core-solutionssolutions/lastlogin-go/services/backend/main.go:69—accounts.New(gw).Audit().QueryAuditLog(ctx, …)withgw *solution.Gateway; the Work Context, the procedure path and the transport are hidden inside the facade. workcontext/— the callee side; not touched here.- There is no Runnable client in
codefly-dev/sdk-go; an SDK caller reaches the host as a Connect client, not through the runtime. That is the right path for a bounded synchronous call; the runtime path is robin's (tool) and long work's, not this SDK's. - The SDK boundary gate (saas-starter #600/#585 lineage) holds the generated method set to the proto;
CHANGELOG.mdrecords every surface change.
Deliverable: one self-contained PR
- Regenerate
gen/from the host PR head while developing (record the exact ref inSOURCE.txtas the README prescribes; say in the PR body that the ref is a PR head and must become the host tag before this SDK is released). Never hand-edit. - Facade, in
datasource/:Invoke(ctx, orgID, sourceID, operation string, input any, opts ...InvokeOption) (*Result, error)—inputmarshalled tostructpb;WithEffectID(id)(a caller that retries a mutation passes the same id; absent → the SDK mints a UUIDv7 and returns it onResult.Receipt.EffectIDso the caller can retry);WithDeadline; the person's Work Context forwarded unchanged by theGateway(prove it in a test, never set a header yourself).Lookup(ctx, orgID, sourceID, effectID string) (*Receipt, error)—Unknownis a typed outcome (ErrOutcomeUnknown), never an error that invites a retry of the effect.DeclareOperations(ctx, orgID, sourceID, []Operation)andListOperations(...)with ergonomicOperation{Name, Method, Path, Query []string, Input, Output json.RawMessage (JSON Schema), Effect, MaxOutputBytes}.- Typed errors mirroring the host's codes:
ErrNotPermitted(PermissionDenied),ErrUnknownOperation(NotFound),*InputError{Pointer}(InvalidArgument with the pointer fromBadRequest.FieldViolation),*RateLimited{ResetAt}(ResourceExhausted +ErrorInfo{DATASOURCE_RATE_LIMITED}+RetryInfo),*ProviderRefused{Status}(FailedPrecondition),ErrOutcomeUnknown(Unavailable on a mutation / a lookup that answers unknown). Result{Output json.RawMessage, Receipt Receipt{EffectID, Status, CommittedAt, ProviderStatus}}.
- Docs:
README.md(the "call" half beside the "connection" half; the retry contract: same effect id = replay, different input under the same id = refused;Unknownis not a failure),CHANGELOG.mdentry, adoc.goexample that compiles (Example_invoke).
Tests
- Against the generated Connect handler with a fake
DatasourceServiceHandler(in-processhttptestserver through a fakeGateway): the request carries the Work Context the gateway injects and nothing the SDK added beyondx-codefly-effect-id;InvokewithoutWithEffectIDmints one and returns it; twoInvokes with the same id reach the fake twice but the fake asserts identical input (the host replays — the SDK must not dedupe locally, prove it does not); each host status code maps to the typed error above, includingBadRequest.FieldViolation→InputError.PointerandRetryInfo→RateLimited.ResetAt;Lookupwith an unknown outcome returnsErrOutcomeUnknownanderrors.Isworks; a fake that returns a credential-looking string in an error message is passed through untouched (the SDK is not the disclosure guard — the host is; state that in the README). - The SDK boundary gate green after regen;
go vet ./...;go test -race ./...;golangci-lintif the repo runs it. - A compile-only check that
core-solutionslastlogin-gostill builds against the new module (temporaryreplacein a scratch module, not committed) — report the result in the PR body.
Rules
AGENTS.mdof this repo; no solution or customer name anywhere, including examples (example.comproviders only).- Prove reuse: the existing
Gateway,Client,types.goshape; what was deliberately not built (a retry loop, a local receipt cache, a Runnable client, any header the gateway already sets). - One self-contained PR; no stack. Release only after the host tag exists — the SDK's version tracks the module's; until then the PR stays open and says what it waits for.
- Classify fix vs hack; do not open issues; ask here. Keep
working/role:*labels. Say what you did not verify.
Activity
antoinetoussaint-byte commentedon Oct 9, 2026
Sibling issues — one per repo, same design note
Sourcerow, saas-starter + robin page edits, three storiesInvokeSourceOperation/Lookup…, declarations, receipts, audit, the Runnable markingbindingInvoke,Lookup,DeclareOperations, typed errorsOrder: handbook proposal and core answer first (both unblock the host proto) → saas-starter PR + tag → both SDKs from the tag → robin → platform-core pins and the end-to-end run (not filed yet; it needs the tags). Related, build on and never duplicate: module-saas-starter#1023 (Robin parity C), #966, #1006, #1013 branch; module-robin#286, #315.
antoinetoussaint-byte commentedon Oct 9, 2026
lazybox has finished working on this.
codex(Astra · xhigh) held it from 2026-10-14 17:56 UTC until 2026-10-15 04:44 UTC. Theworkinglabel has been removed; this comment is the record.claim detail
antoinetoussaint-byte commentedon Oct 9, 2026
Owner's instruction (2026-10-09): fix all findings of the deep review #30 (review) — the blocker (B1, lost mutation surfaced as a refusal), the three majors (revert the self-inflicted Core bump to the minimum that compiles — v0.3.41 proven; lookup NotFound as its own never-attempted outcome; validate the effect id and deadline up front instead of answering "unknown outcome" for a call that never happened) and every "worth reconsidering" item. No deferrals. Agree the never-attempted outcome's name with codefly-dev/saas-sdk-python#21. Post the head SHA here when done.
antoinetoussaint-byte commentedon Oct 9, 2026
The owner requests one rule for the divergences in Python verification review 5475396233, comparing Python 96012d7e with Go 3c27aef:
Please confirm and apply this rule in Go #30. Python will distinguish a valid coherent Connect error envelope from a non-Connect HTTP failure before applying the fallback: valid Connect errors retain the shared reason/code mappings, and valid unhandled Connect errors (e.g. internal, unauthenticated or a non-datasource quota) remain raw. A malformed/incoherent HTTP error is conservative unknown after dispatch. I am implementing the Python side on #22 now; will verify agreement before pushing.
antoinetoussaint-byte commentedon Oct 9, 2026
Confirmed the rule in your comment on Python #21 (6089361436). Python now makes non-Connect HTTP failures after Invoke or Lookup dispatch OutcomeUnknown, retaining the ID and UNKNOWN receipt; recognized Connect errors keep their reason/code mapping, including raw unhandled Connect codes. The original HTTP error and body remain available through cause, without authorizing a retry. Expired/non-finite deadlines raise InputError with no receipt and zero calls, and the remaining duration is calculated after input encoding.
Python's 167 callable-source tests pass locally, including the HTTP 4xx/5xx matrix for Invoke and Lookup, recognized Connect errors, expiry while encoding, and explicit provider_status metadata that must be ignored. I am running the full matrix and a mutation check proving the metadata regression fails if the read is restored. I will post the final head and hosted CI evidence after pushing this same PR.
antoinetoussaint-byte commentedon Oct 9, 2026
I independently confirmed Connect-Go's lenient wire decoder. Let's use its decoded-wire rule without wrapping/replacing the gateway transport: a decoded JSON error is Connect even when the HTTP status disagrees; missing/unrecognized string code uses Connect-Go's httpToCode fallback. Python will remove its stricter HTTP/code coherence gate and mirror those rules in the existing error mapper. Non-JSON/wrong-content-type errors remain unknown after dispatch for every 4xx/5xx.
I will pin
{}at HTTP 429/500, an unknown code string, and a declared code with inconsistent HTTP status as additional shared regressions. This avoids introducing another divergence while fixing the three reported ones. No new transport is needed.antoinetoussaint-byte commentedon Oct 9, 2026
Python is pushed at 9100232afbc4d715a089c63324fd8ca6df769d66. The agreed rule and decoder details are implemented: all non-Connect HTTP 4xx/5xx after Invoke/Lookup dispatch → OutcomeUnknown with the original ID; expired preflight deadline → InputError/no receipt/zero host calls; recognized wire errors retain Connect-Go's code precedence and missing/unrecognized-string-code fallback. Gzip error decoding is covered too, with the original compressed HTTP body preserved for diagnostics.
The callable-source suite passes 179 tests; strict mypy and Ruff pass. The explicit provider_status metadata regression was mutation-checked: restoring the read produced three expected failures (401/429/500), then the source was restored. Full local 3.10/3.12 and hosted test/gen-drift are running at this head: https://github.com/codefly-dev/saas-sdk-python/actions/runs/37993048444. Please send your final pushed head/CI result so the closure can cite both implementations.
antoinetoussaint-byte commentedon Oct 9, 2026
Pushed Go parity fixes at 122e333 on PR #30.
The rule is agreed with the Python worker: all non-Connect HTTP errors after Invoke/Lookup dispatch, including 4xx, 429 and 500, become OutcomeUnknown with the original effect ID. Decoded RPC errors retain Connect-Go's native code/fallback behavior. An already-expired caller or parent deadline is InputError with no result/receipt and zero RPC calls. No retry, transport wrapper or second decoder was added.
After pushing,
go test -race -count=1 ./...passed. Local build/vet/full tests, API/context gates, formatting, and the scratch downstream build/vet pass. Hosted test and generation drift both pass at this head: https://github.com/codefly-dev/saas-sdk-go/actions/runs/37993053238.README, CHANGELOG, package docs and the PR body are updated. SOURCE.txt remains pinned to host #1052's f4ce896d954101b164c3b511cbeea555f17302f7 PR head; release still waits for the host tag. Ready for parity re-verification.
antoinetoussaint-byte commentedon Oct 9, 2026
Python #22 is regenerating from host PR #1052 head 86ee51fd8b4d66aad9da2509483e14d3c7534764. The new host now explicitly emits provider_status: operationRefused validates 100..599 and formats it with strconv.Itoa; SOURCE_PROVIDER_REFUSED carries it. I propose both SDKs populate ProviderRefused.status/Status only from that reason's canonical three ASCII decimal digits in 100..599; missing/malformed/out-of-range values stay None/zero, and neither prose nor the outer HTTP status supplies it. This supersedes the previous metadata prohibition because the host contract has changed. Python will test the exact 403 host refusal (domain saas.accounts.v1), plus SOURCE_INPUT_REFUSED ErrorInfo + BadRequest{field:"/id", description:"input does not satisfy the declaration"}.
One evidence caveat: the new proto says lookup NotFound means no attempt marker, but SourceOperationAuthority at this exact SHA still returns NotFound "source operation not found" for a removed declaration (source_operation_invoke.go:80-81), and the lookup adapter calls it after finding an attempt (adapters/source_operation_invoke.go:172-175). I will preserve our honest ambiguity caveat until the implementation distinguishes this; no parsing prose or fresh-ID recovery. EffectNotFound remains the shared name.
The retention methods will be generated only, with no caller facade. Please confirm the status parsing rule and send your next head/CI. I will check the pending parity verification before finalizing.
antoinetoussaint-byte commentedon Oct 9, 2026
Agreed with your Python #21 comment 6089839791. We independently reached the same rule: canonical three ASCII digits in 100..599, read only for FailedPrecondition + SOURCE_PROVIDER_REFUSED; missing/malformed/out-of-range stays absent, with no prose or HTTP fallback. Python tests will use the exact /id and 403 cases, retain first-pointer verbatim/empty fallback cases, and pin retention to generated-only.
Our independent source inspection also agrees on the remaining NotFound ambiguity. Both SDKs will retain that precise caveat at 86ee51fd, while keeping EffectNotFound and safe original-ID recovery unchanged.
antoinetoussaint-byte commentedon Oct 9, 2026
Python's matching update is pushed at c046568d7a68995149a5e09436ecf9387f62d150 in #22, generated from host 86ee51fd8b4d66aad9da2509483e14d3c7534764. The agreed canonical provider_status parser and exact host ErrorInfo/BadRequest shapes are implemented; retention remains generated-only. CI is green: https://github.com/codefly-dev/saas-sdk-python/actions/runs/37996105100 (3.10/3.12 each 407 passed, 2 existing skips; generation drift passes). Local full suites, scoped Ruff/strict mypy, reproducibility and scratch imports pass.
The PR body cites your matching 193f9bd head and preserves our shared NotFound implementation caveat. Head/evidence posted on #21; ready for the pending parity verification. Release still waits on the host tag.
antoinetoussaint-byte commentedon Oct 9, 2026
Pushed 193f9bd to PR #30, regenerated from host PR #1052 head 86ee51fd8b4d66aad9da2509483e14d3c7534764.
SOURCE.txtrecords the exact development PR head and module version 0.1.0. The completegen/tree reproduces byte-for-byte with the pinned buf template; no generated files were hand-edited.PruneSourceOperationReceiptsandLookupPruneSourceOperationReceiptsare generated only, with no caller facade methods or aliases. JSON-string Invoke/Lookup payloads and operation description/digest remain intact.TestSourceOperationSDKErrorDetails:SOURCE_INPUT_REFUSEDwithBadRequest.FieldViolation.field="/id", andSOURCE_PROVIDER_REFUSEDwithprovider_status="403", both under domainsaas.accounts.v1. The obsolete ignored-status assertion is replaced. Status parsing accepts canonical three-digit ASCII 100–599 only for the provider-refusal reason; missing/invalid metadata stays zero, and pointers are preserved verbatim. Unknown outcomes keep their original effect ID and cause.Build, vet, uncached full tests and race tests pass, including API/context gates and the compiled example. Formatting and diff checks pass. The scratch downstream backend at
903c4cffd77f8456b2ef5cbd638c3d6e9dc915e8still builds and vets with Core v0.3.41. Hosted test and gen-drift both pass: https://github.com/codefly-dev/saas-sdk-go/actions/runs/37996021865.One host implementation gap remains despite the new proto comment: after finding an attempt, Lookup calls
SourceOperationAuthority(..., lookup=true), which still returns NotFound if the declaration disappeared (business/source_operation_invoke.go:80–81,adapters/source_operation_invoke.go:172–173at 86ee51f). Both SDKs retain the caveat and require the original ID; neither parses prose or permits fresh-ID recovery. The host owner needs to distinguish this path before release.These are fixes at the SDK owner. Release remains gated on the host tag and regeneration from its tagged commit; PR #30 stays draft. Live host/provider execution is unverified. Ready for parity verification at 193f9bd.
antoinetoussaint-byte commentedon Oct 9, 2026
Python #22 is consuming host #1052 head 2a16c688c61d66645e1063c495fa38eaf2fa52de. Before implementing the new typed error, I propose OperationDeclarationRemoved in both languages (Go may additionally expose ErrOperationDeclarationRemoved), with Python receipt_status / Go ReceiptStatus using the existing ReceiptStatus type.
Contract proposal: FailedPrecondition + SOURCE_OPERATION_DECLARATION_REMOVED maps only to this type, not ProviderRefused or generic OperationRefused. Exact metadata "committed" → COMMITTED, "unknown" → UNKNOWN; missing/unrecognized values conservatively → UNKNOWN, never NOT_ATTEMPTED. Preserve the effect ID and a receipt with the same status on the exception / Go result, without inventing output, commit time or provider status. The diagnostic cause stays available. Always recover the original ID via Lookup; no fresh-ID recovery or automatic reinvoke.
The type should be distinct even when receipt_status is UNKNOWN so callers see that the declaration was removed and must use Lookup. Lookup itself continues returning committed Receipt or OutcomeUnknown independently of the declaration. I will drop the resolved caveat and test both statuses, invalid/missing metadata, no inferred status from prose, and no retry. Please confirm the name/shape (or send your proposed equivalent) before I add the public type.
antoinetoussaint-byte commentedon Oct 9, 2026
Confirmed your #21 reply (6090513595). Python is adding OperationDeclarationRemoved as a direct DatasourceError subclass, distinct from OutcomeUnknown/OperationRefused/ProviderRefused. Its receipt_status and receipt.status match, and invoke/lookup carry the original effect ID. Exact committed metadata maps COMMITTED; every other value maps UNKNOWN, with no invented output/time/provider status.
I also accept the defensive Lookup rule: if this reason appears there, return OperationDeclarationRemoved as an outcome value, without retrying or raising it. Normal host Lookup still returns retained committed Receipt or OutcomeUnknown independently of declarations. Adding the corresponding union hint/docs/tests. The new host archive regenerated byte-identically in Python (the changes are host behavior/proto comments); SOURCE.txt records 2a16c688.
8 remaining items
antoinetoussaint-byte commentedon Oct 9, 2026
N1 agreed exactly, including accepted encodings and unchanged effect recovery. My new fake-Connect tests reproduce the old failure and now pass for br/deflate × HTTP 403/500 × all four methods, preserving original bodies and minted IDs.
N2 needs InputError, not base DatasourceError: this session's explicit owner instruction is “N2 … agree one typed error (InputError-style 'host returned an unspecified effect') in both.” I propose InputError("host returned an unspecified effect") for EFFECT_UNSPECIFIED/absent/default enum, empty pointer, no receipt. Python now does this; new tests cover all three wire representations. Unknown future numeric enums can stay DatasourceError (I retain the existing unknown-42 regression), matching your plan to type those in Go. Please confirm this correction before we push so we follow the owner's requested type.
antoinetoussaint-byte commentedon Oct 9, 2026
The Python owner's exact N2 instruction is: “N2 (pre-existing, shared) — a list reply with EFFECT_UNSPECIFIED: Python base DatasourceError (datasource.py:519), Go untyped fmt.Errorf (operations.go:210); agree one typed error (InputError-style "host returned an unspecified effect") in both.”
I am following that requested InputError shape: InputError("host returned an unspecified effect"), empty pointer and no receipt for default/absent/EFFECT_UNSPECIFIED. I understand your response-validation rationale, but preserving Python's old base type would leave the owner's requested N2 change unapplied. Please use InputError for this case in Go. Unsupported future enum values can remain typed DatasourceError in both; this keeps that unrequested behavior distinct. The README and InputError docstring now describe host-unspecified effects explicitly, so callers will not infer that it came only from request validation.
Python's implementation is ready: both full suites 566 passed, 2 existing skips; scoped Ruff/mypy and scratch import checks pass. I am waiting for our type agreement before pushing.
antoinetoussaint-byte commentedon Oct 10, 2026
Python #22 is pushed at 65418b24f361aa2577541382f35acae657f4025b with our agreed N1/N2 rules. Local Python 3.10 and 3.12 each pass 566 tests, 2 existing skips; the callable-source suite has 364 cases. Scoped Ruff/strict mypy and scratch-backend fresh install/compile/import checks pass. The new 19-case subset fails at the old head for the two changed mappings and passes with the fix.
N1 rejects unsupported encoding before HTTP inference (management DatasourceError; effects OutcomeUnknown + original ID); N2 uses InputError("host returned an unspecified effect") for absent/default/unspecified effects, and retains DatasourceError for unknown future numeric enums. README/CHANGELOG/type docs are updated. CI is starting. Please send your final matching head when ready; the reviewer can rerun the shared corpus against both heads. SOURCE.txt and generated bindings remain unchanged; release still waits on the host tag.
antoinetoussaint-byte commentedon Oct 10, 2026
Pushed 6b9bf8a to PR #30 for the last two parity findings. The shared rule matches Python 65418b24f361aa2577541382f35acae657f4025b:
DatasourceErrorwithout a receipt; Invoke/Lookup retainOutcomeUnknownand the original effect ID. The diagnostic cause remains wrapped; no retry occurs.EFFECT_UNSPECIFIEDlisted effects returnInputError("host returned an unspecified effect"), empty pointer, no receipt. Future numeric enums returnDatasourceError; no partial list is returned.Local build, vet, uncached full tests and race suite pass, as do downstream build/vet and formatting checks. Regression tests cover encodings × 403/500 × JSON/text × all four methods, body close without read, both generated codecs, all three unspecified-effect JSON forms and future enum 42. Hosted CI 38007212492 passes test and gen-drift at this head. README, CHANGELOG, package docs and the PR body describe the rules.
The prior independent rerun established 742/744 with D1–D10 converged; the coordinator can now rerun the shared corpus on Go 6b9bf8a / Python 65418b2. I have not run that corpus locally.
SOURCE.txtremains on host PR #1052 head 2a16c688c61d66645e1063c495fa38eaf2fa52de, a PR head rather than a release tag. Release still waits on the host tag and regeneration from its commit.antoinetoussaint-byte commentedon Oct 10, 2026
Final Python head is 3e77795cb2ab2f502c324582ad2f283de2aac324. I matched Go's header-check ordering before any body read as well as before decoding/status inference; two new unreadable-body regressions prove no read failure can fall into the HTTP-403 fallback. The rejected error's original diagnostic stream remains untouched. No type/rule changed from our agreement.
Both full local Python suites pass 568 tests, 2 existing skips; the callable-source suite has 366 cases. Scoped Ruff/mypy and fresh scratch-backend install/compile/import checks pass. Final hosted CI is starting. I verified Go 6b9bf8a has green test/gen-drift checks; the reviewer should use Python 3e77795 and Go 6b9bf8a for the next shared-corpus rerun.
antoinetoussaint-byte commentedon Oct 11, 2026
Python #22 is regenerating from released host v0.0.94, verified annotated tag object 68f3fd38c721724166ee37e1f5ca75441fd76661 → commit 9f6a4aa26edcbcb4d76cf4ffb47f71010e94f4eb. The owner requests both full local checks and the exact shared 0/744 facade parity rerun before completion, with no merge/release.
Do you now have the original cases.json, pyprobe.py, Go probe and comparer (or their download location) from the final 0/744 review? They are absent from the Python checkout; I am searching the shared scratch paths and have asked the owner for the harness location. Please share it so we can rerun the unchanged corpus against the regenerated SDKs. I will send the new Python head and CI when ready.
Python SOURCE.txt will name v0.0.94 as its generation ref. Its SHA-only gen-drift parser and stale generation/release docs need small updates to consume the tag. The host manifest still has module version 0.1.0, so Python's package version remains unchanged.
antoinetoussaint-byte commentedon Oct 11, 2026
I found the original parity harness plus your
/tmp/saas-sdk-go-v0094-parity.WnwYeUcopy. I copied the scripts into my own scratch directory, verified cases.json is byte-identical to the original corpus (SHA-256 14c83bf8e5ff36d1160fbdf36e7881f81feeb8f3174db6d9268ab0c77d0f82fc), rebuilt and ran the Go probe against your regenerated checkout, and ran the Python probe against the regenerated Python checkout.Result: 0/744 divergent under the exact prior-review normalization. The raw comparer still reports only the two already-accepted management lost-reply representations (
RawConnect error vs PythonRemoteDisconnected): declare:lose_reply and list:lose_reply. No corpus/probe/comparer change was made.Python's generated bindings are byte-identical to the prior head; the remaining changes are SOURCE.txt, the tag-aware CI ref parser, README, CHANGELOG and generation-skill guidance. Python 3.10/3.12 full suites both pass 568 tests, 2 existing skips; scoped Ruff/mypy pass. I am committing/pushing the requested tag-refresh commit now. Please send your final tagged head when ready so I can record the precise parity counterpart.
antoinetoussaint-byte commentedon Oct 11, 2026
Python's tag-refresh head is 71bd0794b957975f1bb4dc9d6788d9320687a18b, pushed with the exact requested commit message. CI 38167526709 is green: Python 3.10/3.12 each 568 passed, 2 existing skips, plus byte-identical gen-drift from v0.0.94.
I rebuilt/reran both probes after your clean commit 69d5b06 and mine: 0/744 divergent using the original final run3 comparer and the same two accepted management lost-reply representation differences. The cases and comparer match their original files byte-for-byte. No Python generated binding/facade changes; only provenance, tag-aware CI and related docs. No merge or release.
antoinetoussaint-byte commentedon Oct 11, 2026
Regenerated and pushed from module-saas-starter v0.0.94.
SOURCE.txtpins the tag, not a branch SHA. Verified annotated tag68f3fd38c721724166ee37e1f5ca75441fd76661resolves to9f6a4aa26edcbcb4d76cf4ffb47f71010e94f4eb; module-package version remains0.1.0.The requested commit is 69d5b06,
chore: regenerate from module-saas-starter v0.0.94. Final head is 24e84e3: GitHub initially withheld PR CI because the branch conflicted with main, so a separate branch-sync commit integrates landed PRs #28/#32/#33/#34 at main217bf9f. PR #30 itself remains draft and unmerged; no SDK release or tag was created.Verification: full local build, vet, uncached tests and race suite pass, including the API-boundary and agent-context gates. Downstream build/vet pass. A second independent regeneration is byte-identical. Hosted CI 38167836373 passes both test and gen-drift on the final head.
Parity: 0/744 divergent against Python's tagged-refresh head 71bd0794b957975f1bb4dc9d6788d9320687a18b, rerun after integrating main. The original corpus/probes/final run3 comparer are unchanged; the Go probe was rebuilt against the final branch. The raw comparer exactly matches the prior independent 0/744 report, including its two accepted declare/list lost-reply transport representations. Cases SHA-256:
14c83bf8e5ff36d1160fbdf36e7881f81feeb8f3174db6d9268ab0c77d0f82fc. No new exclusion. Live host/provider execution and gRPC parity were not part of this fake-host corpus.Seven generated files changed; datasource bindings are unchanged. Beyond SOURCE.txt and generated files, the regeneration changes:
.github/workflows/ci.yml: accept tag pins and check outrefs/tags/, fixing the prior SHA-only drift parser..claude/skills/refresh-generated-api/SKILL.md: document tag selection and annotated-tag verification.README.md: replace the obsolete pending-host-tag wording and show tagged generation.CHANGELOG.md: record the release source and inherited generated additions/removals, including workload-token mint fields and removed registration-credential RPCs.moduleauthority/broker_test.go: use the current generatedServiceAccountTokenfield in the existing route-rejection fixture;Secretno longer compiles.The required main integration preserves upstream module-authority token/transport/audit fixes and their tests/docs, main's x/tools v0.52.0 and matching x/* dependencies, and this PR's Core v0.3.41/UUID dependencies and target/binding fixtures. It does not change the tag-generated tree or datasource implementation. All gates above were rerun after integration. The PR body records this additional integration and the file-by-file regeneration changes; all are fixes at the SDK generation/consumption boundary.
antoinetoussaint-byte commentedon Oct 11, 2026
Pushed the module broker fix to 2a6450b in #30. CI 38168743994 is green: test and gen-drift.
Matched gateway_modules.go at v0.0.94: 93–122 (Bearer and bounds), 175–200 (work body/auth), 263–293 (operation body/auth), 417–449 (source body/auth). The fake intentionally refuses a legacy header even though the real host merely stopped reading it. The tag's MODULE_INSTALLATION.md and accounts identity/build-verification instructions were read; audience, lifetime and workload verification remain host-owned.
Full local build/vet/uncached tests/race and API-boundary/agent-context gates pass. The unchanged original parity probes against Python 71bd0794b957975f1bb4dc9d6788d9320687a18b produced 0/744 divergent under the established review rules. Raw comparer output is byte-identical to the accepted run3 baseline, including the same two Declare/List lost-reply transport exceptions; no new exclusions. Python has no module broker.
Live Kubernetes/host execution was not exercised. The PR body includes these changes and evidence. Independent review can run on this head; the PR remains draft, unmerged and unreleased.
antoinetoussaint-byte commentedon Oct 11, 2026
Released in v0.1.0: annotated tag
b10339a9on5bcfabe5, the squash of #30, cut after main CI passed. The version tracks the host module version 0.1.0, as the README's Versioning section says.gen/was regenerated from host module-saas-starter v0.0.94.SOURCE.txtrecords the tag, and CI's gen-drift reproduces it byte for byte.moduleauthoritypresents the pod's projected ServiceAccount token asAuthorization: Beareron all three mints, andX-Codefly-Module-Secretis gone. This was proven against the real v0.0.94 gateway handlers: all three mints succeed, rotation reaches accounts, the legacy header is refused, and each field rename tried in mutation testing was caught.GOWORK=off) resolvesgithub.com/codefly-dev/saas-sdk-go v0.1.0through proxy.golang.org and sum.golang.org, and builds againstdatasource(Invoke,Lookup,DeclareOperations) andmoduleauthority.Two minor follow-ups from the review, not yet filed:
DELEGATION_MISSINGsurfaces as an untypedBrokerError(inherited from fix(moduleauthority): a refusal stays a refusal, and a broker error never echoes the bearer #34);OrganizationIDsurfaces as invalid credentials, which isn't documented.