Skip to content

Migrate constructor/factory methods to MyType.factory.my_method - #105

Open
rjhuijsman wants to merge 3 commits into
mainfrom
rjh.factory-namespaced-constructors
Open

rjhuijsman wants to merge 3 commits into
mainfrom
rjh.factory-namespaced-constructors

Conversation

@rjhuijsman

@rjhuijsman rjhuijsman commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Fixes #106

Before this change, constructors lived directly on state classes (e.g. Account.open()). A user-defined constructor named ref would have silently collided with the built-in MyType.ref(), and the framework could never add a new factory method without risking a clash with an existing user constructor — which a customer also can't rename or delete, leaving them permanently unable to upgrade.

This PR namespaces every state type's constructor (a.k.a. factory) methods under a factory attribute, so await MyType.create(context) becomes await MyType.factory.create(context). That frees the top level of the generated state class for framework methods we may want to add later (e.g. a future MyType.query(...)), and prevents naming collisions with built-in methods. How a constructor is declared (factory=True, or the constructor proto option) is unchanged — only the call surface moved.

Reviewer hint: the GitHub diff of the *.j2 template files looks big, but very little actually changed — it's ~all mechanical. In Python the constructor and idempotency-scope methods are simply indented into a new nested class _Factory (literally +4 spaces on everything). In TypeScript the same methods had to be moved to keep them contiguous. No control flow or logic changed in either language. The only "functional" changes are a new class to wrap these methods, and a .factory in places they're called. The *.golden.* files are regenerated codegen output.

I suggest you review the commits individually.

@aviator-app

aviator-app Bot commented Jul 21, 2026

Copy link
Copy Markdown

Current Aviator status

Aviator will automatically update this comment as the status of the PR changes.
Comment /aviator refresh to force Aviator to re-examine your PR (or learn about other /aviator commands).

This PR is not ready to merge (currently in state pending): this PR has a review with changes requested (the review must be approved or dismissed before merging).

Pending Status Checks


See the real-time status of this PR on the Aviator webapp.
Use the Aviator Chrome Extension to see the status of your PR within GitHub.

@rjhuijsman
rjhuijsman requested a review from benh July 22, 2026 10:01
@rjhuijsman rjhuijsman self-assigned this Jul 22, 2026
@rjhuijsman
rjhuijsman marked this pull request as ready for review July 22, 2026 10:01
@aviator-app

aviator-app Bot commented Jul 22, 2026

Copy link
Copy Markdown

This pull request can't be queued because it's currently a draft.

@rjhuijsman
rjhuijsman force-pushed the rjh.factory-namespaced-constructors branch 2 times, most recently from 02fa0c9 to 5e1d259 Compare August 3, 2026 12:00
@rjhuijsman

Copy link
Copy Markdown
Contributor Author

@benh poke!

rjhuijsman and others added 3 commits August 19, 2026 16:15
Before this change, constructors lived directly on
the state class: a user-defined constructor named
`ref` silently collided with the built-in
`MyType.ref()`, and the framework could never add
a new factory method without risking a clash with
an existing user constructor — which a customer
could not rename or delete, leaving them
permanently unable to upgrade.

This commit namespaces every state type's
constructor (a.k.a. factory) methods under a
`factory` attribute, so `await
MyType.create(context)` becomes `await
MyType.factory.create(context)`. That frees the
top level of the generated state class for
framework methods we may want to add later (e.g. a
future `MyType.query(...)`), and prevents naming
collisions with built-in methods. The way a
constructor is declared (`factory=True`, or the
`constructor` proto option) is unchanged; only the
call surface moved.

IMPORTANT REVIEWER HINT: the GitHub diff of the
`*.j2` files is big, but very little actually
changed: a bunch of methods got indented inside a
new `_Factory` class, that's it. For Python that's
literally just 4 spaces added to everything, for
TS some code had to move to be contiguous but
still remains unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xyvD8vLQ9dTwtFMexovJo
The `upgrade` skill rolls fragments from
`skills/upgrade/migrations/next/` into each release's migration notes.
This adds the fragment for the constructor-namespacing change so an app
upgrading past it knows to move its constructor calls: it gives
grep-able before/after patterns for `Foo.create(context, ...)` ->
`Foo.factory.create(context, ...)`, plus the idempotency-scope and
custom-constructor variants.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xyvD8vLQ9dTwtFMexovJo
The previous commit changed where
constructor/factory methods live; this commit
changes all the callers to use the new syntax.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xyvD8vLQ9dTwtFMexovJo
@rjhuijsman
rjhuijsman force-pushed the rjh.factory-namespaced-constructors branch from 5e1d259 to e2eafed Compare August 19, 2026 16:19
@rjhuijsman

Copy link
Copy Markdown
Contributor Author

@benh poke again! Let's get this landed!

return cls.idempotently(
how=IMPORT_reboot_aio_idempotency.ALWAYS,
)
factory = _Factory

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.

My only request is to make this a function so that if we ever find ourselves wanting to provide more functionality we can do so. I think that means we can keep returning _Factory from that function and that if in the future we instead end up creating instances of _Factory then the only code that would have to change are folks that stored <StateType>._Factory but I don't think that should be anyone and that is an easy thing for coding agents to do as part of a release migration.

@benh benh 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.

Shoot I lied, one more thing that needs to get done is to ask your coding agent to update any of the static analysis that we've since introduced as part of the dashboard for tracking factory calls. Better yet, just ask it to review all commits since this PR was created to confirm that there aren't any other change that depend on the previous semantics of factories/constructors. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Constructor/factory methods collide with type-class-level methods

2 participants