Skip to content

feat(moduleauthority): expose module audit emission - #28

Merged
antoinetoussaint-byte merged 4 commits into
codefly-dev:mainfrom
gael-obin:feat/runtime-boundary-compatible
Oct 10, 2026
Merged

antoinetoussaint-byte merged 4 commits into
codefly-dev:mainfrom
gael-obin:feat/runtime-boundary-compatible

Conversation

@gael-obin

@gael-obin gael-obin commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Expose moduleauthority.Client.EmitAuditEvent(ctx, AuditEvent) through the existing authenticated module-authority transport. A producer can persist its complete event and stable idempotency key, emit it, and settle its outbox only after the host acknowledges it. The SDK preserves fields, credentials and host error codes; it refreshes rejected authentication once and never automatically retries an uncertain effect.

The current host deduplicates by (tenant, event_type, idempotency_key) without comparing payloads. Callers must never reuse a key for another intent. A successful call acknowledges the audit write or an existing key, not webhook delivery. Receipt lookup and runtime-boundary verification are deferred to an integrated host contract from codefly-dev/module-saas-starter#1046; this PR preserves all artifact, installation and delegation APIs already on main. gen/ and SOURCE.txt match main exactly and reproduce from its recorded source; no generated file was hand-edited.

Classification: fixes at the SDK owner. The audit facade reuses callAsModule and generated bindings, golang.org/x/tools is updated so the API boundary gate can read Go 1.27.2 export data, and generic release ownership replaces downstream product references. Consumer behavior and recovery limits are documented in README.md and CHANGELOG.md; gate and regeneration guidance is updated in AGENTS.md and .claude/skills/refresh-generated-api/SKILL.md.

Maintainer-side review and fixes were done by Antoine's coordinator worker.

Validation: local build, vet, test, race, formatting, public API boundary and agent-context checks; byte-for-byte generation with buf 1.73.0; boundary gate also checked with Go 1.27.0. Deliberately dropping the idempotency key, stripping module authentication, or retrying unavailable effects makes audit regression tests fail; every mutation was restored. Tests cover exact request transport, preservation across client recreation, one authentication refresh, permission refusal, missing authority and uncertain effect errors.

The SDK tests do not establish host database restart safety or deployed gateway wiring. Those guarantees belong to the host transaction and the producer's durable outbox. No live hosted deployment, release, or tag was exercised.

Review: #28 (comment)

Main was merged without rebasing or force-pushing. PR #32 owns audit declarations and gateway transport and remains open at handoff. Both hosted checks (test and gen-drift) passed at 1b0fbc32fb763a9a383cd703c7323084f5e35d9f: https://github.com/codefly-dev/saas-sdk-go/actions/runs/38092844274. GitHub subsequently reported #28 merged by antoinetoussaint-byte as 7fe05b85970956d74fa3b7122ac1874d30a37f7d; this worker did not issue a merge command. PR #32 must now integrate the new main.

Review result: #28 (comment)

@antoinetoussaint-byte

Copy link
Copy Markdown
Contributor

@gael-obin — heads-up: I'm taking this PR to merge. obin-ai/module-record-store#115 needs moduleauthority's audit emission (#28) and declarations (#32) in an upstream commit Go can fetch; today it pins 278a7a6, which exists only on your fork. A worker will review this PR, merge main into its branch (no rebase or force-push), fix what the review finds, and post the review here. I'll merge once CI is green. If you'd rather land it yourself, or something here shouldn't go upstream, say so on this PR.

@antoinetoussaint-byte

antoinetoussaint-byte commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Review of saas-sdk-go #28

Reviewed head: 903f0256c94259b5b64613214424b03fac1d7b2b.
Reviewed base: a7b6e72cbd9d9aaa70831b6488fa867feaded007 (main).
Merge base: 38f5724822db7d148a8084ed256c97c0d87d19e9.

Phase 1 was completed before implementation changes, from a full, non-shallow, non-promisor clone at the exact PR head. The original checkout and the review clone are clean after restoring the deliberate mutations below.

The useful change is a thin module-authority facade: forward an original capability for live boundary attestation, emit a registered audit event with a caller-retained stable key, and recover its receipt under current authority. The new methods correctly reuse callAsModule, the existing broker, the generated client, and sdk-go's opaque Work Context token. No second verifier, credential cache, retry engine, outbox, or SDK receipt store was introduced.

Most of the 5,118 additions are complete generated bindings, including intervening platform catalogue, organization, invitation, datasource and audit-visibility contracts. Those are not hand-written feature sprawl: buf 1.73.0 with this repository's pinned template reproduced the entire head gen/ byte for byte from cc7c530c9b09455bf00ac15f2558817363396c7b. Removing individual generated additions would be the wrong fix. However, the source selection is incompatible with present main, as finding 1 details.

  1. P1 — The selected proto generation cannot preserve current consumers. SOURCE.txt:1; gen/saas/accounts/v1/module_capabilities.pb.go:1666. The recorded source cc7c530c9b09455bf00ac15f2558817363396c7b is fetchable from the upstream repository, but belongs to the unmerged host #1046 experiment. Relative to main's source 21f139ee433695ae2129899f265c59b99f6661af, it lacks seven exported messages: ExecutableArtifactContract, ExecutableArtifactIdentity, ModuleExecutableArtifactRequest, ModuleRevokeExecutableArtifactRequest, ModuleExecutableArtifactResponse, ModuleCurrentInstallationRequest, and ModuleCurrentInstallationResponse. Keeping this generated side during the merge breaks the artifact and installation facades already on main; keeping main's generated side loses the two new RPCs. Current host main also no longer carries the experiment's runtime-boundary mechanism. Remediation: consume a reviewed owner-side contract that integrates both histories, then regenerate; or explicitly narrow this PR to the already-supported EmitAuditEvent facade and defer receipt/boundary APIs to host #1046. Do not splice generated descriptors or implement a second host mechanism in the SDK. PR feat(moduleauthority): expose gateway transport and audit declarations #32 separately owns audit declaration and gateway transport and must be preserved when integrated.

  2. P1 — The API boundary gate fails with the installed Go 1.27.2 toolchain. go.mod:10. GOWORK=off go test -race ./... fails all three internal/apiboundary tests because golang.org/x/tools v0.49.0 cannot decode export data version 5 (maximum supported version 4). The same gate and the complete test suite pass with GOTOOLCHAIN=go1.27.0, confirming a toolchain/importer compatibility defect rather than a generated API alias defect. This is inherited at the PR head, but blocks the required local gate. Remediation: update the owning importer dependency to a release supporting the active Go version, verify both supported toolchains, and retain the boundary fixtures. Do not weaken or skip the gate.

  3. P2 — Consumer/process documentation still names a downstream product. README.md:199; .claude/skills/refresh-generated-api/SKILL.md:106. Both tie this generic SDK's release-generation process to a named downstream solution's epic. This is inherited but violates the requested generic repository boundary and gives consumers the wrong ownership reference. Remediation: describe release generation as owned by module-saas-starter and this SDK without downstream product names; retain the exact regeneration and versioning instructions.

Audit semantics were traced into the recorded host implementation: ModuleEmitAuditEvent prepares and authorizes intent, then uses WithOrgTx/WithControlPlane; DurableAuditEmitter.EmitTx reserves the fingerprint/key and writes the event in the caller's transaction; LookupAuditEffect reads the existing fingerprint/event ID without writing. Keys are scoped by tenant and event type. Changed intent and historical key-only reservations fail precondition in that experiment. An empty lookup remains inconclusive. The SDK preserves the complete fields/key and host error codes, refreshes only unauthenticated module credentials once, and does not retry unavailable effect outcomes. Durability belongs to the host database; these SDK tests do not establish database restart safety or retention behavior.

Fail-closed review: the boundary facade accepts no caller-chosen tenant/boundary, carries the forwarded viewer token only in the request, authenticates separately as the module, rejects missing response fields, and propagates denial. The recorded host verifies the forwarded signature/current authority and live registration; consumers still must compare the returned identity with their independently verified context and enforce scopes. This contract is unavailable on current host main, per finding 1.

Mutation evidence (all mutations restored): removing the emitted idempotency key makes TestAuditEmissionAndReceiptUseModuleAuthority fail with audit intent changed in transport; accepting a response missing just one boundary field makes TestRuntimeBoundaryIndependentModuleAuthority fail; removing the independent module credential makes both tests fail unauthenticated. Restored GOTOOLCHAIN=go1.27.0 GOWORK=off go test ./... passes. Thus the tests detect real transport/security regressions, although the audit receipt fake is not a durable host integration test.

Formatting recheck: gofmt -l . and formatting the original audit source both produce no differences. An initial formatting finding was withdrawn after this direct check.

Not verified in phase 1: a real host/database restart, concurrent database receipt reservations, or the deployed gateway; no such end-to-end result is claimed. GitHub returned no workflow runs for the reviewed SHA, and the PR is conflicting, so there was no pending run to approve yet.

Next: fix findings 2–3 and resolve main's changes without rebasing. Finding 1 needs the coordinator's contract/scope decision before selecting the final generated tree; no issues, tags, releases, or merges will be created by this worker.

@antoinetoussaint-byte antoinetoussaint-byte changed the title feat(moduleauthority): expose verified boundary and audit receipt APIs feat(moduleauthority): expose module audit emission Oct 10, 2026
@antoinetoussaint-byte
antoinetoussaint-byte marked this pull request as ready for review October 10, 2026 22:53
@antoinetoussaint-byte

antoinetoussaint-byte commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Review result for saas-sdk-go #28

Final reviewed head: 1b0fbc32fb763a9a383cd703c7323084f5e35d9f.
Base merged and verified: a7b6e72cbd9d9aaa70831b6488fa867feaded007.
Original reviewed head: 903f0256c94259b5b64613214424b03fac1d7b2b.
Upstream merge observed during handoff: 7fe05b85970956d74fa3b7122ac1874d30a37f7d.

The fork branch now contains a self-contained EmitAuditEvent facade against the contract already on main. The final diff is 305 additions / 25 deletions across nine files; gen/, SOURCE.txt, datasource aliases, and existing artifact, installation and delegation APIs are identical to main. The PR title and body describe this narrowed scope and include the requested coordinator-worker attribution.

The boundary and receipt experiment was not carried forward: its source lacked seven messages required by current consumers, and current host main does not serve those two RPCs. They remain dependent on an integrated owner-side contract from host #1046. This PR makes the supported emission API available for a durable producer relay without inventing an SDK-side verifier or receipt store.

  1. Original P1, incompatible source generation — resolved in merge commit 1b0fbc3. SOURCE.txt:1; moduleauthority/audit.go:46. Read the conflicting histories: 8ae74ef introduced delegation references, 13d46a1 artifact consent, 44124ad installation identity, while f28fe43/903f025 introduced the experimental boundary/receipt source. Regenerated the whole tree from main's exact 21f139ee433695ae2129899f265c59b99f6661af source using buf 1.73.0 and the pinned template, then verified no generated difference from main. Resolved the shared fake by retaining main's existing methods and adding only audit emission. Kept main's datasource alias documentation and changelog history. No descriptor was hand-merged. The unsupported new methods were removed rather than deleting existing consumer APIs. Remediation is complete for the explicitly narrowed emission scope.

  2. Original P1, Go importer incompatibility — resolved in c249f20. go.mod:10; AGENTS.md:74. Updated golang.org/x/tools from v0.49.0 to v0.52.0 and its required dependencies. The formerly failing API boundary gate now passes under Go 1.27.2 and Go 1.27.0, with its negative fixtures intact. The original failure and version-controlled reproduction are recorded in the phase-1 review; no check was skipped or weakened.

  3. Original P2, downstream product coupling — resolved in c249f20. README.md:239; .claude/skills/refresh-generated-api/SKILL.md:106. Replaced the downstream product epic references with generic module-saas-starter/SDK release ownership, keeping the regeneration and versioning procedure. README.md and CHANGELOG.md also explain the supported API and its actual recovery semantics. The initially suspected formatting defect was withdrawn after direct gofmt verification; it was not counted as a fixed defect.

Reuse review: production emission uses the existing callAsModule, credential cache, generated RPC and protobuf Struct conversion. Core v0.3.32's similarly named types in provider/sink and toolbox/session describe credential-sink operations and toolbox lifecycle records; neither represents this host audit RPC or its idempotency key. There is no second authority or audit delivery mechanism here.

A relay must persist its complete event and stable key before sending and reuse both after a restart. The current host deduplicates by (tenant, event_type, idempotency_key) without comparing payloads. A nil SDK error acknowledges the host write or a previously used key, not downstream webhook delivery. A timeout may follow a committed write. Only unauthenticated module credentials are refreshed once; all other host codes are preserved without automatic effect retry. Documentation makes these limits explicit.

Local verification at the final head passed: GOWORK=off go build ./..., go vet ./..., go test ./..., go test -race ./..., gofmt -l . (empty), and git diff --check. There is one non-fixture Go module and no separate repository lint configuration. The API boundary gate also passed with GOTOOLCHAIN=go1.27.0. A second scratch regeneration exactly matched the final tree.

Final mutation checks all failed as intended and were restored: dropping the idempotency key broke request/restart/refresh assertions; retrying Unavailable caused four attempts where two explicit emits were expected; stripping the module credential caused authentication and carrier assertions to fail. Regression tests additionally exercise permission refusal, permanently rejected module authentication, unavailable/deadline/internal/precondition errors, missing authority without a broker call, and complete intent preservation across client recreation. The original boundary test mutation was also effective before that unsupported API was removed.

Hosted CI passed at the final head: run 38092844274, with both test and gen-drift successful. The fork workflow initially required action; this worker approved it using the administrator account. GitHub reports the branch mergeable.

Not verified: a live host/database restart, a deployed gateway, or end-to-end webhook delivery. SDK fakes prove transport behavior, not host database durability. This worker created no tag, release, issue, or PR merge. The fork was updated by an ordinary push; main was merged, never rebased or force-pushed.

During the final handoff, after this worker marked the green PR ready and posted this result, GitHub reported #28 merged by antoinetoussaint-byte at 2026-10-10T22:54:06Z, as 7fe05b85970956d74fa3b7122ac1874d30a37f7d. No merge command or merge API was issued by this worker. The upstream fetch confirms that merge on main. GOWORK=off go list -m -json resolved that upstream SHA to v0.0.3-0.20261010225405-7fe05b859709, and go mod download -json downloaded its module archive successfully with no replacement or local workspace.

PR #32 is still open at 83b5d5621a791314757c1b0edae6d444de7c979c. Coordinator: integrate and verify #32 against the new main commit so consumers needing both emission and declarations can pin one upstream main SHA. The emission API itself is now on upstream main; receipt/boundary APIs remain deferred to the integrated host contract.

@antoinetoussaint-byte
antoinetoussaint-byte merged commit 7fe05b8 into codefly-dev:main Oct 10, 2026
2 checks passed
@antoinetoussaint-byte

Copy link
Copy Markdown
Contributor

Merged at 7fe05b8 (reviewed head 1b0fbc3, CI green). The scope was narrowed to the EmitAuditEvent facade. The boundary/receipt RPCs were not carried forward because current host main does not serve them and they depend on host #1046; see the review result above. @gael-obin, that experiment is still on your branch history (903f025) if you want to bring it back once the host side lands.

@antoinetoussaint-byte

antoinetoussaint-byte commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

lazybox has finished working on this. codex (Astra) held it from 2026-10-10 22:41 UTC until 2026-10-20 00:26 UTC. The working label has been removed; this comment is the record.

claim detail
Lazybox-Claim-Device: effacd542b611010656e
Lazybox-Claim-Session: 182a2a0ad9
Lazybox-Claim-Workspace: github-codefly-dev-saas-sdk-go-28
Lazybox-Claim-Agent: codex
Lazybox-Claim-Model: Astra
Lazybox-Claim-Started: 2026-10-10T22:41:16Z
Lazybox-Claim-Heartbeat: 2026-10-20T00:26:19Z
Lazybox-Claim-Expires: 2026-10-19T16:49:29Z
Lazybox-Claim-Released: 2026-10-20T00:26:19Z

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.

2 participants