Repository navigation
Gate fixes: deploy truthfulness for gateway errors, repeated exports and progress overlay (PR #100 findings) #101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b7830b8
81c5982
b888f6f
119ef22
0f0be6f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2679,14 +2679,16 @@ function getFileNameFromPath(filePath) { | |
| const projectSourceCache = new Map(); | ||
|
|
||
| // File writes whose provisioning outcome is unconfirmed, per cache key — | ||
| // each dirty path maps content -> { uncertain, verified }: `uncertain` counts | ||
| // provision attempts that may still write that content (a lost/dropped | ||
| // request is not proof the runner stopped), and `verified` credits confirmed | ||
| // writes an export sighting must consume first. An export showing content X | ||
| // can retire an uncertain X-write only when no verified X-write explains the | ||
| // observation — so a confirmed retry can never clear an earlier attempt whose | ||
| // identical write may still land over a newer edit. While any entry is | ||
| // outstanding, fresh exports are never cached. | ||
| // each dirty path maps content -> { uncertain, verified, explainedByVerified }: | ||
| // `uncertain` counts provision attempts that may still write that content (a | ||
| // lost/dropped request is not proof the runner stopped), and `verified` | ||
| // credits confirmed writes an export sighting must consume first. A sighting | ||
| // of content X consumes a verified X-credit before it can retire an uncertain | ||
| // X-write, and once a verified X-write has explained an X-sighting, | ||
| // `explainedByVerified` marks the sighting as spent evidence: a later export | ||
| // of the same unchanged X is the same fact, not a new landing, so it can never | ||
| // retire an uncertain X-write whose identical content may still land. While | ||
| // any entry is outstanding, fresh exports are never cached. | ||
| const projectSourceDirtyWrites = new Map(); | ||
|
|
||
| // Unconfirmed sync pushes whose underlying request is still in flight, per | ||
|
|
@@ -2930,12 +2932,13 @@ async function provisionMissingCodeFiles( | |
| ); | ||
|
|
||
| // A stream that ended (or a body that carried) no definitive result leaves | ||
| // the remote decision ambiguous. There are two distinct cases which must not | ||
| // be flattened: a server that explicitly refused the request (a 403/5xx | ||
| // `response.ok === false`) has made a definitive decision — the write did not | ||
| // happen — so that is a FAILURE, not an unknown outcome; only an ok response | ||
| // whose stream dropped before a result (or a client wait expiry) leaves the | ||
| // remote state genuinely unknown and must be reported UNCONFIRMED. | ||
| // the remote decision ambiguous. An explicit 4xx is a definitive pre-write | ||
| // refusal — the request was turned away before any write — so it is a | ||
| // FAILURE, not an unknown outcome. A 5xx is no such proof: a gateway can | ||
| // answer 502/503/504 after forwarding the request to the runner, which may | ||
| // already be deploying, so a 5xx — like an ok response whose stream dropped | ||
| // before a result, or a client wait expiry — leaves the remote state | ||
| // genuinely unknown and must be UNCONFIRMED. | ||
| if (!result.finalResultReceived) { | ||
| if (deployOutcomeOfStreamResult(result) === DeployOutcome.FAILED) { | ||
| // Not marked remoteRefusal: the refusal comes from our deploy runner, | ||
|
|
@@ -2945,9 +2948,16 @@ async function provisionMissingCodeFiles( | |
| `FlutterFlow custom class provisioning failed (HTTP ${result.httpStatus}).`, | ||
| ); | ||
| } | ||
| // The cause must match what actually happened. A non-ok status (a 5xx, | ||
| // typically a gateway) was received, so the runner answered — it did not | ||
| // drop the connection — and the message names the status. Only an ok | ||
| // response whose stream ended without a result is a dropped connection. | ||
| 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."; | ||
| throw new UnconfirmedDeployError( | ||
| "The connection to the FlutterFlow deploy runner dropped before it reported a result. " + | ||
| "The deploy may still be finishing on the server; open your FlutterFlow project to reconcile " + | ||
| `${cause} The deploy may still be finishing on the server; open your FlutterFlow project to reconcile ` + | ||
| "before retrying.", | ||
| ); | ||
| } | ||
|
|
@@ -3086,14 +3096,21 @@ async function resolveProjectPubspec(apiClient, newDependencies = {}) { | |
| // This fresh export is the authoritative read: an observed content | ||
| // first consumes a verified write credit (the sighting is explained by | ||
| // a confirmed provision), and only retires an uncertain write when no | ||
| // verified write could have produced it. | ||
| // verified write could have produced it. A sighting explained by a | ||
| // verified write is spent evidence — a later export of the same | ||
| // unchanged content is the same fact, so it must not retire the | ||
| // uncertain write whose identical content may still land. | ||
| for (const [path, contents] of [...dirty]) { | ||
| const observed = projectSource.files.get(path); | ||
| if (observed !== undefined) { | ||
| const record = contents.get(observed); | ||
| if (record) { | ||
| if (record.verified > 0) record.verified -= 1; | ||
| else record.uncertain -= 1; | ||
| if (record.verified > 0) { | ||
| record.verified -= 1; | ||
| record.explainedByVerified = true; | ||
| } else if (!record.explainedByVerified) { | ||
| record.uncertain -= 1; | ||
|
Comment on lines
+3111
to
+3112
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Repeated exports erase pending retries When two identical provisions remain unconfirmed, Learn moreProvisioning 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 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 Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| } | ||
| if (record.uncertain <= 0 && record.verified <= 0) { | ||
| contents.delete(observed); | ||
| } | ||
|
|
@@ -6772,6 +6789,7 @@ document.addEventListener("DOMContentLoaded", async () => { | |
| updateProgressFromState(state); | ||
| } else if (state === CommitState.SUCCESS || state === CommitState.ERROR) { | ||
| updateProgressFromState(state); | ||
| if (commitProgressHideTimer) clearTimeout(commitProgressHideTimer); | ||
| commitProgressHideTimer = setTimeout(() => { | ||
| commitProgressHideTimer = null; | ||
| hideCommitProgress(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔍 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.