Withhold a render failure the environment caused, at the row that publishes it - #6075
Withhold a render failure the environment caused, at the row that publishes it#6075backspace wants to merge 2 commits into
Conversation
…lishes it The indexer stores a failed render as the card's content, so a render that resolves current realm source against a bundle predating an export turns a few minutes of deploy overlap into an error document served from cache to every anonymous reader until something reindexes the row. The decision has to be made where the row is written. A prerender server can delay a write but never prevent one — answering retryably only spends the client's retry budget and then the same row lands with a different message, and the manager prunes a server that answers 5xx, walking its registry as it goes. So the server states what it knows and the write site acts on it. The server is the only place holding both tokens at the moment of the render, so it reaches the conclusion: a missing export that survived a re-render on a pool that still cannot be shown to have been on the shell being served describes the environment, not the card. It marks the response and returns the failure unchanged. The write site tests for the mark's presence and nothing else. It does not re-derive the conclusion, so the rule has one implementation rather than two that drift, and absence means "no verdict" rather than "attributable" — nothing is withheld by default. When the mark is present and a prior published row exists, the row keeps the content the last good pass left: `pristine_doc` and its neighbours were already carried forward there, and this only declines to stamp `has_error` and `error_doc` over them. The published `search_doc` stays too, since the error's sparse one describes a render whose result is not being published. Two gates keep the suppression from hiding a real break. It requires a prior published row, because a brand-new card has no good content to protect and withholding its error would leave nothing at all. And it requires the missing export to *be* the failure rather than merely appear among the console errors merged onto it — the broader test is right for driving one more render, where being wrong costs a render, and wrong for withholding a row, where being wrong hides a genuine break. Tests state both directions, since the difference is the whole point: a pool that never reaches the current shell is marked, a genuine break on a recycled pool is not, and a timeout that merely mentions a missing export is not. Substituting the broad predicate for the narrow one fails that last case and only that case — the first draft of these tests did not distinguish them, which is why it is there.
Host Test Results 1 files ±0 1 suites ±0 2h 34m 46s ⏱️ + 26m 50s Results for commit 31db0f6. ± Comparison against earlier commit 54f6e69. Realm Server Test Results 1 files ± 0 210 suites +2 1h 12m 30s ⏱️ +34s Results for commit 31db0f6. ± Comparison against earlier commit 54f6e69. |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 54f6e69b9c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Two corrections, one of which meant the withholding did nothing in production. Suppressing `boxel_index.has_error` is not enough to stop the row reading as errored. `effectiveHasError()` is `COALESCE(i.has_error, FALSE) OR (ph.error_doc IS NOT NULL AND ph.generation >= i.generation)`, and `effectiveErrorDoc()` serves `ph.error_doc` in that case — so a current error on the prerendered-HTML channel publishes the failure whatever the index channel says. Postgres uses the split channel by default, so the previous version withheld nothing where it mattered. `writePrerenderedHtmlRow` now applies the same gate, keeping the preserved render instead of stamping an error over it, and gated on there being a preserved render for the same reason the other channel gates on `pristine_doc`. The verdict also has to say which rows it covers. One visit produces the instance and file rows independently, and they fail independently: a card render can hit the stale bundle while the file extraction beside it fails for a reason of its own. A response-level flag withheld both, hiding that second, genuine failure. So the mark is now the list of row types whose own failure was the missing export, and each write site requires its own type to be named. An empty list is not written at all, because absence has to keep meaning "no verdict" rather than becoming an empty array a reader might mis-test. A page that never became usable is the one case that covers both rows: neither render happened, so the failure belongs to both rather than to one. Tests follow the scoping. The route case that matters pairs a stale-bundle card failure with an unrelated file-extract failure and requires the verdict to name only `instance` — the shape that would have over-suppressed before.
The indexer stores a failed render as the card's content, so a render that resolves current realm source against a bundle predating an export turns a few minutes of deploy overlap into an error document served from cache to every anonymous reader until something reindexes the row.
The decision has to be made where the row is written. A prerender server can delay a write but never prevent one — answering retryably only spends the client's retry budget and then the same row lands with a different message, and the manager prunes a server that answers 5xx, walking its registry as it goes. So the server states what it knows and the write site acts on it.
The server is the only place holding both tokens at the moment of the render, so it reaches the conclusion: a missing export that survived a re-render on a pool that still cannot be shown to have been on the shell being served describes the environment, not the card. It marks the response and returns the failure unchanged.
The write site tests for the mark's presence and nothing else. It does not re-derive the conclusion, so the rule has one implementation rather than two that drift, and absence means "no verdict" rather than "attributable" — nothing is withheld by default. When the mark is present and a prior published row exists, the row keeps the content the last good pass left:
pristine_docand its neighbours were already carried forward there, and this only declines to stamphas_erroranderror_docover them. The publishedsearch_docstays too, since the error's sparse one describes a render whose result is not being published.Two gates keep the suppression from hiding a real break. It requires a prior published row, because a brand-new card has no good content to protect and withholding its error would leave nothing at all. And it requires the missing export to be the failure rather than merely appear among the console errors merged onto it — the broader test is right for driving one more render, where being wrong costs a render, and wrong for withholding a row, where being wrong hides a genuine break.
Tests state both directions, since the difference is the whole point: a pool that never reaches the current shell is marked, a genuine break on a recycled pool is not, and a timeout that merely mentions a missing export is not. Substituting the broad predicate for the narrow one fails that last case and only that case — the first draft of these tests did not distinguish them, which is why it is there.