Repository navigation
Gate fixes: deploy truthfulness for gateway errors, repeated exports and progress overlay (PR #100 findings) - #101
Conversation
…thful A 5xx from the provisioning endpoint no longer classifies as a definitive pre-write refusal: a gateway can answer 502/503/504 after forwarding the request, so the outcome stays UNCONFIRMED and the possibly-written files stay dirty until an export proves them (only 4xx is still FAILED). An export sighting already explained by a verified write is spent evidence: a second export of the same unchanged content can no longer retire an earlier uncertain write whose identical content may still land, so the snapshot stays uncached until that attempt reports its own result. A new deploy starting inside the terminal state's 1s hide delay cancels the previous deploy's hide timer instead of having its progress overlay closed by it.
|
This PR does not match any of the 1 configured review trigger rule. |
provisionMissingCodeFiles' no-final-result branch still described a 403/5xx `response.ok === false` as a definitive pre-write refusal. Only a 4xx is FAILED now; a 5xx stays UNCONFIRMED because a gateway can answer 502/503/504 after forwarding the request to the runner. Comment-only: no behavior change.
…esult provisionMissingCodeFiles reported a no-result 5xx as "the connection to the FlutterFlow deploy runner dropped before it reported a result" — but an HTTP 502 was actually received, and the status was discarded. The cause sentence was false for exactly the case the 5xx handling exists for. The unconfirmed message now says the runner returned HTTP <status> without reporting a result when a non-ok status arrived, and keeps the dropped-connection wording only when an ok response stream ended with no result. The reconcile-before-retry advice is unchanged in both. The 502 e2e test now pins the truthful text: it must name HTTP 502 and must not claim the connection dropped.
…-truthfulness Resolve the app.js commitStateChange conflict in favour of the base side, which owns the delayed-hide timer at module scope behind cancelCommitProgressHide() (also called from commitProgress.start()). The PR's function-local copy of the timer is dropped: it would shadow the module-scope handle, so the start-path cancel and the terminal branch would operate on two different variables. Keep the PR's one-line timer clear on the terminal branch. Base only cancels a pending hide when a commit *starts*, so two terminal states in quick succession leave the first timer pending; it fires early, nulls the shared handle, and a later cancelCommitProgressHide() can no longer reach the second timer.
| } else if (!record.explainedByVerified) { | ||
| record.uncertain -= 1; |
There was a problem hiding this comment.
🔴 Repeated exports erase pending retries
When two identical provisions remain unconfirmed, resolveProjectPubspec retires both after repeated exports show one landing. The unchanged content consumes an uncertain credit on every export, so a later retry can overwrite a newer edit behind a cached snapshot.
Learn more
Provisioning attempts that time out stay tracked as uncertain because the runner can still write after the browser stops waiting. markProjectSourceDirty increments the uncertain count for every attempt, including retries of the same file content. If two such attempts exist, a single remote write produces one observable content transition. Every fresh export of that unchanged content then decrements the count again, even though the other attempt can still run. resolveProjectPubspec caches the export once the count reaches zero, hiding a later write from subsequent deploy planning.
Example: Attempts A and B both time out while provisioning gauge_model.dart with content X. A writes X; two exports showing X clear both credits. A new edit Y is deployed, but B later writes X, and a subsequent deploy reads the cached snapshot instead of X.
Recommended fix: Track whether an observed path/content transition has already been used to retire an uncertain attempt, not only whether a verified write explained it. Allow another retirement only after a distinct observable transition or a definitive late result for that attempt. Preserve the existing verified credit handling for confirmed retries.
Was this helpful? React with 👍 or 👎 to provide feedback.
| const cause = | ||
| result.httpRejected && typeof result.httpStatus === "number" | ||
| ? `The FlutterFlow deploy runner returned HTTP ${result.httpStatus} without reporting a result.` | ||
| : "The connection to the FlutterFlow deploy runner dropped before it reported a result."; |
There was a problem hiding this comment.
🔍 Gateway errors retain timeout wording
An immediate HTTP 502 now reports its status, but showCommitUnconfirmedModal still says the browser stopped waiting. The terminal title reads like a timeout despite a received response.
Was this helpful? React with 👍 or 👎 to provide feedback.
…te-deploy-truthfulness
01a11be
into
milestone/stu-implement-updated-ui-ux
Findings addressed
G1 — Greptile P1, "Gateway errors hide uncertain writes" (src/provisionStream.js:177-179):
Fixed in
deployOutcomeOfStreamResult: only a 4xx is still a definitive pre-write refusal (FAILED). Every 5xx is now UNCONFIRMED — a gateway can answer 502/503/504 after the request reached the runner. The caller's existing UNCONFIRMED path then invalidates the project-source cache and marks the files dirty (markProjectSourceDirty), so a retry must re-export and cannot silently re-provision.G2 — Greptile P1, "Repeated exports clear pending writes" (app.js:3086-3089):
Fixed in
resolveProjectPubspec's dirty-sighting loop: an export sighting that consumes a verified credit is markedexplainedByVerifiedon the record. A later export of the same unchanged content is the same fact, not a new landing, so it can no longer retire the uncertain credit. The uncertain write is resolved only by its own late result (success → converts to a verified credit consumed by the next sighting; provable pre-write failure → retired), so the snapshot stays uncached while the write may still land.D1 — Devin, "Previous deploy hides active progress" (app.js:6744-6746):
Fixed in the
commitStateChangelistener: the terminal state's 1s hide timer is now tracked incommitProgressHideTimerand cleared when a new deploy reports PREPARING/VALIDATING/PUSHING, so a stale timer can no longer close the new deploy's overlay.Fail → pass evidence (base head 6dd8edb)
The source files (
app.js,src/provisionStream.js) were reverted to base head while the new tests were kept; the same commands were then re-run on the fixed head. No other files differ.Base head — unit:
Base head — e2e (
--retries=0):Fixed head b7830b8:
The break each test catches:
deployOutcomeOfStreamResulttoFAILEDfor allhttpRejectedfails the test (observed above).UnconfirmedDeployErrorand force a fresh export (exportCalls1→2); base throws a plainErrorand leaves the cached snapshot.exportCalls4, not 3); a late success from the first attempt then resolves it and caching resumes at 5.#commit-progress-overlaystill carries.openpast the 1s timer and 0.25s visibility transition.CI results on pushed head b7830b8
CI=1 npm testCI=1 npm run buildCI=1 CCC_TEST_PORT=3104 npm run test:uistu389-hero-mark-fieldWebGL timing, unrelated; passes 3/3 in isolation with--retries=0 --repeat-each=3)CI=1 npm run test:accessibilityCI=1 npm run test:deploy-guardCI=1 npm run test:proxiesCI=1 python3 scripts/scan_bundle_for_leaks.pyFunctions edited (line ranges are post-change)
app.jsresolveProjectPubspec— dirty-sighting loop at lines 3080-3104; and theprojectSourceDirtyWritesmodel comment at lines 2673-2684 (same bookkeeping feature).app.jsDOMContentLoadedcallback'scommitStateChangelistener — lines 6738-6772 (timer declaration + listener).src/provisionStream.jsdeployOutcomeOfStreamResult— lines 148-190;httpRejectedcomment inreadProvisionResponse— lines 93-104.src/provisionStream.test.js(two tests updated/added),e2e/stu380-deploy.spec.js(one new G1 test, one new D1 test, G2 test extended).No other region of
app.jswas touched.git statusafter restoring generated artifacts shows only these four files modified.Not implemented / out of scope
provisionMissingCodeFiles(app.js ~2940) is outside this brief's ownership. A gateway 502 now surfaces the existing unconfirmed wording ("connection … dropped before it reported a result … may still be finishing … reconcile before retrying"), which does not claim nothing was written, but it does not name the HTTP status.src/deployOutcome.jswas not touched: itsFAILEDdoc already states that 5xx are UNCONFIRMED, which the fix now honours.Judgement calls / uncertainties
explainedByVerifiedis deliberately conservative: once a verified write has explained a content sighting, repeated sightings of that content can never retire the uncertain credit — even if the content later changes away and back. Only the attempt's own result resolves it..openclass rather than computed visibility because the overlay'svisibilitytransition (0.25s) is still mid-flight at the 1s hide-delay boundary; the class is the settled evidence that the timer ran.