Uh oh!
There was an error while loading. Please reload this page.
refactor(project): tighten the ProjectEvent and create() contracts - #1969
Merged
Conversation
ProjectEvent was a bag of three optional fields, two of which (subprocessOutput, project) had no producer and no consumer. Narrow it to the single field that is actually emitted and make it required, so consumers stop guarding on `if (event.message)`. Typing create()'s return as Project, rather than leaving the generator's TReturn as `any`, surfaced a latent hole: the returned runtimes came straight from the template's loosely-typed `unknown[]` spec section. Read the project back through resolve() instead, which validates against ProjectSpecSchema and does what the original comment already claimed.
codecov-commenter
commented
Aug 11, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@## refactor #1969 +/- ##
=========================================
Coverage 96.80% 96.80% =========================================
Files 306 306 Lines 17073 17073 =========================================
Hits 16527 16527 Misses 546 546 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
tejaskash
approved these changes
Aug 11, 2026
Hweinstock
approved these changes
Aug 11, 2026
| // schema-validated instead of the template's loosely-typed spec sections. | ||
| const project = await this.resolve({ filePath: destination }); | ||
| if (!project) { | ||
| throw new ProjectStateError( |
Contributor
There was a problem hiding this comment.
OOS here but ProjectStateError feels pretty vague to me. What do you think of replacing it with something like ProjectValidationError for when reading a project fails?
ContributorAuthor
There was a problem hiding this comment.
Ahh yes that makes sense, I will make a note and have it out as a followup!
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Groundwork for
agentcore project build, split out so the contract change is reviewable on its own.What
ProjectEventwas a three-field bag with every field optional:subprocessOutputandprojectwere never written and never read — I checked every producer and consumer. Onlymessagewas ever used, and because it was optional thecreatehandler had to guard it (if (event.message)) on every iteration. So the type is now just:and the guard in
handlers/project/create/index.tsis gone.createalso declaredAsyncGenerator<ProjectEvent>, leavingTReturnas the defaultany. It is nowAsyncGenerator<ProjectEvent, Project>.The type hole that tightening exposed
Naming the return type surfaced a real mismatch:
createwas building its return value out ofTemplateSpec.runtimes, which isunknown[], whileProject.runtimesisProjectRuntime[].anyhad been hiding it.Rather than cast,
createnow reads the project back throughresolve():That honours a comment already sitting in the code ("Return the same shape resolve() would: a created project is a resolvable one"), and means the returned runtimes are schema-validated instead of being the template's loosely-typed spec sections passed through unchecked.
The matching
as Projectcast inmanager.test.tsis dropped too, so the test now type-checks the real thing.Verification
bun test— 1061 pass, 0 failtsc --noEmitclean,oxlintcleanNo behaviour change; the only user-visible difference is that progress messages are no longer conditionally skipped, and they were never absent in practice.