Skip to content

[obvious-fleet] Backend: the result names which stages ran as stand-ins - #294

Draft
SamGu-NRX wants to merge 3 commits into
alphafrom
obv/burst14-bs-result-names-stand-ins
Draft

SamGu-NRX wants to merge 3 commits into
alphafrom
obv/burst14-bs-result-names-stand-ins

Conversation

@SamGu-NRX

Copy link
Copy Markdown
Owner

fleet-packet: burst14-bs-result-names-stand-ins

Human author: Sam Gu (sgu07966@gmail.com)

What changed

On a stubbed orchestration (HSS_ORCH_STAGE_STUBS=1), a run still closes with a verdict, but some of its stages ran stand-in modules under server.orchestrator.stubs — and nothing downstream said so. The stand-in result stage literally wrote <html><body>stub review</body></html> (server/orchestrator/stubs/result.py:52), so a partly stubbed answer was easy to mistake for a real one.

Now the real result composer reads one impl/<stage>.json marker per run stage from its inputs (impl/ joined STAGE_INPUTS["result"] in server/orchestrator/graph.py), each carrying the pinned body {"schema": "hss-stage-impl/v1", "stage": ..., "implementation": "real"|"stand-in", "callable": ...}. result.internal.json gains stageImplementations (stage → real | stand-in | unknown; unknown means no marker, as for runs composed before markers existed) and a sorted standIns list. The reviewer page names the stand-in steps next to the true decision. result.json is unchanged.

Why

Reviewers and downstream consumers need to know which numbers came from real measurement work before they trust a verdict or decide a retake is worthwhile. The markers are written by the orchestration's stage runner (packet burst14-bs-stage-selection, separate PR); this PR builds the reader side against that contract, so the two land independently.

How it works

flowchart LR
    R[Stage runner] -- "one marker per stage" --> M[(impl/&lt;stage&gt;.json)]
    M -- "hydrated by 'impl/' input" --> C[Result composer]
    C --> I["result.internal.json<br/>stageImplementations + standIns"]
    C --> P["review.html<br/>'Stand-in steps: …'"]
Loading

One line to notice: a stage with no marker reads as unknown, so old runs compose unchanged. result always reads as real — the composer runs inside it. A marker without the pinned schema (or with an implementation that is neither real nor stand-in) stops the composition with a loud impl_invalid error naming the file, because a mis-published marker would otherwise read as a trustworthy name.

UI changes

The reviewer page, same screen, state and viewport (1440×900), composed from the committed synthetic fixture:

Before — the header jumps from the true decision straight to the failure code:

Reviewer page before: no stand-in line

After — with objects and reads marked as stand-ins, the page says so in plain words:

Reviewer page after: stand-in steps named

No video: this change adds a static text line; the page's point-cloud rotation predates it.

Verification

Tested at head 8057732e (base alpha @ 969d4e93), cloned fresh, all commands from backend/:

  • Focused tests: uv run --frozen --extra api pytest server/result/tests/test_stand_ins.py — 5 passed. Each of the five fails against the pre-change composer (verified by checking out HEAD~1 of compose.py): all real; two stand-ins; no impl dir → every stage unknown; a marker without the pinned schema refused by name; result.json byte-identical with and without markers.
  • Result suite in full: pytest server/result/tests — 71 passed.
  • make result-golden — exit 0, ok synthetic photo reject; the regenerated result.internal.json carries all eleven stages unknown plus result: real, standIns empty.
  • uv run --frozen --extra api ruff check and ruff format --check on the three changed files — clean.
  • Full make test once — 4 failed, 1511 passed, 19 skipped, 14 errors (674.98s, exit 2):
Known pre-existing failures on alpha, named separately rather than fixed
FAILED server/eval/tests/test_gates.py::test_route_over_the_bar_is_known_until_expiry
FAILED server/eval/tests/test_gates.py::test_refresh_rewrites_pins_after_a_committed_edit
FAILED server/eval/tests/test_gates.py::test_offline_table_skips_the_engine_and_passes_the_unpatched_reference
FAILED server/eval/tests/test_gates.py::test_committed_fixtures_are_scored_against_their_labels
ERROR tests/test_capture_cold_restart.py (14 collection errors)
  ImportError: cannot import name 'load_receipt' from 'scripts.replay_capture'
  at scripts/capture_cold_restart.py:82

The four gate failures are the known SD-96 expired-window cases (Sam decides that window), and the fourteen cold-restart errors are the pre-existing load_receipt import break. Both live outside this packet's paths and reproduce on plain alpha; no failure set difference was introduced.

Not verified: no end-to-end run against a real orchestrated run publishing markers — the publishing side belongs to burst14-bs-stage-selection and is not open yet, so markers were exercised through test fixtures and the CLI --impl flag. No Modal, GCS, R2, deploy, or real-capture data was touched, and no iOS build was run (no iOS change). The optional app-facing field below is a proposal only; nothing app-visible changed.

What's left: the marker publisher PR (burst14-bs-stage-selection), the SD-96 window decision, and the PR itself — opened by the maintainer under their account; this branch is pushed and stops there.

App-facing field proposal (not implemented)

result.json stays byte-identical because the iOS decoder pins its shape (PR #285, test_capture_device_decoder_contract.py). The additive change I would propose for the app: two optional top-level fields, stageImplementations (same object as the internal record) and standIns (sorted array), both absent-safe so old payloads decode unchanged. Screen copy on the result screen, under the decision banner, as a dim caption: "Parts of this scan ran in reduced mode (objects, reads), so their results are not real measurements." — shown only when standIns is non-empty.

Alternatives considered

  1. Derive provenance from RunRecord.degraded / stage statuses. Rejected: degraded conflates "never ran" with "ran a stub", and the state store is not part of the result stage's inputs — the composer would guess where it should read.
  2. Put the fields straight into the app-facing result.json. Rejected for now: that shape is pinned by the iOS decoder contract, and a reviewer-only need does not justify risking the app. Proposed as an additive optional field above instead.
  3. Reader-side marker files (this PR). Won: the contract is pinned and shared, compose stays a pure reader with one loud failure mode, unknown falls out naturally for runs composed before markers existed, and the two packets land independently.

Risk

Low. result.json is byte-identical (pinned test), the reviewer line renders only when standIns is non-empty, and a run with no impl/ input composes exactly as before. The one new failure path — a malformed marker stopping composition — is deliberate: a run whose provenance cannot be proven should close for manual review, not sail through as a real answer. The 14 cold-restart collection errors and 4 SD-96 gate failures in the full suite pre-date this change.

Checklist

  • The scope is focused; related changes belong together
  • I explained what changed and why
  • I included before/after images for visible changes
  • I included a video for motion or interaction changes — N/A, the visible change is a static text line; no motion was added

🔗 Obvious Project · 🧵 Obvious Thread · 🔀 Obvious PR Artifact


Opened by the maintainer from the Obvious thread's own description, so every review bot reviews it (CodeRabbit skips PRs authored by bots). The work and its commits are by Obvious.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>

The result composer reads every impl/<stage>.json marker the
orchestration publishes into the result stage's inputs, refuses a
marker without the pinned hss-stage-impl/v1 schema, and records
stageImplementations plus a sorted standIns list in the internal
record. The reviewer page names the stand-in steps next to the true
decision. result.json is unchanged: the iOS decoder pins it.
result/'s STAGE_INPUTS gains impl/ so the markers hydrate.
All real, two stand-ins, no impl dir, a marker without the pinned
schema refused, and result.json byte-identical with and without impl
files. The five fail against the pre-change composer.
@SamGu-NRX

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Oct 16, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the size:M 30-99 effective changed lines. label Oct 16, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T18:26:14.258729Z 8057732 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8057732e68

ℹ️ 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".

"verdicts/",
"reads/reads.json",
"scale/scale.json",
"impl/",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Publish implementation markers before composing results

Adding impl/ to the result inputs only makes the composer read markers; this commit does not create them. run_stage publishes only the files listed in each stage's returned StageResult.artifacts, and neither the real stages nor the stub stages emit impl/<stage>.json, so normal orchestrated runs hydrate no implementation directory and _stage_implementations always reports every non-result stage as unknown with an empty standIns list. The new result metadata therefore never identifies which stages actually ran as stand-ins.

Useful? React with 👍 / 👎.

Comment on lines +224 to +225
"stageImplementations": stage_implementations,
"standIns": stand_ins,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Route stub runs through the metadata-aware composer

When HSS_ORCH_STAGE_STUBS is enabled, stage_callable selects server.orchestrator.stubs.result.run for the result stage because result is not stubs_exempt; that stub writes its own result.internal.json and review.html and never calls compose_result. Consequently the newly added stageImplementations, standIns, and reviewer-page warning are absent on the very runs whose stages are stand-ins, even if implementation markers are supplied.

Useful? React with 👍 / 👎.

implementation = doc.get("implementation")
if implementation not in {"real", "stand-in"}:
raise ResultError("impl_invalid", f"{path}: implementation is neither real nor stand-in")
implementations[str(doc.get("stage") or path.stem)] = implementation

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject markers with unknown stage names

For a malformed or stale marker whose stage value is a typo or arbitrary string, this assignment silently adds a new key to stageImplementations instead of rejecting the marker. The resulting internal record and review page can report a bogus stand-in while leaving the actual stage as unknown, undermining the trust guarantee described by this parser's schema validation; the stage should be checked against StageName (and ideally the filename) before insertion.

Useful? React with 👍 / 👎.

@SamGu-NRX

Copy link
Copy Markdown
Owner Author

@greptileai review this at plus

@greptile-apps

greptile-apps Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5 Tier: plus

[Medium impact] Adds stage implementation tracking to result composition.

The PR appears safe to merge, with two non-blocking improvements to marker checks.

Fix All in CodexFindings

  1. P2 A stand-in can disappear ▶
  2. P2 Bad markers lose useful errors ▶
Fix with agent prompt
### Issue 1
backend/server/result/compose.py:374
The reader trusts `stage` without checking that it matches the filename or belongs to `StageName`. An `objects.json` marker naming `reads` as a stand-in can be overwritten by a later `reads.json` marker naming it real. The internal record and reviewer page then hide that stand-in.

Reject unknown or mismatched stage names with `impl_invalid`, and add a test for conflicting markers.

```suggestion
            stage = doc.get("stage")
            if not isinstance(stage, str) or stage not in implementations or stage != path.stem:
                raise ResultError("impl_invalid", f"{path}: stage must be a known stage matching the filename")
            implementations[stage] = implementation
```

### Issue 2
backend/server/result/compose.py:372-373
A marker containing `"implementation": []` or an object raises `TypeError` at this set-membership check. It never reaches `ResultError("impl_invalid", ...)`, so the failure loses both the marker filename and the promised error code. This makes the failed run harder to diagnose.

Check that `implementation` is a string before testing its value, and cover arrays and objects in the tests.

```suggestion
            if not isinstance(implementation, str) or implementation not in {"real", "stand-in"}:
                raise ResultError("impl_invalid", f"{path}: implementation is neither real nor stand-in")
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds reader-side support for stage markers without changing the app-facing result.

  • The result now names stages that ran as stand-ins.

Acknowledged scope from SamGu-NRX:

  • The marker publisher is deferred to a separate PR, and end-to-end publishing was not verified.
  • App-facing fields are a proposal only because the existing decoder contract is pinned.
  • The four SD-96 gate failures and fourteen cold-restart errors are identified as pre-existing.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A["Stage marker inputs"] --> B["Result composer"]
    B --> C["Internal stage names and stand-ins"]
    C --> D["Reviewer warning"]
    B --> E["Unchanged app-facing result"]
Loading

Reviews (1) · Last reviewed commit: "style(result): ruff-format the stand-in ..." · Reviewed by Greptile

implementation = doc.get("implementation")
if implementation not in {"real", "stand-in"}:
raise ResultError("impl_invalid", f"{path}: implementation is neither real nor stand-in")
implementations[str(doc.get("stage") or path.stem)] = implementation

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 A stand-in can disappear

The reader trusts stage without checking that it matches the filename or belongs to StageName. An objects.json marker naming reads as a stand-in can be overwritten by a later reads.json marker naming it real. The internal record and reviewer page then hide that stand-in.

Reject unknown or mismatched stage names with impl_invalid, and add a test for conflicting markers.

Suggested change
implementations[str(doc.get("stage") or path.stem)] = implementation
stage = doc.get("stage")
if not isinstance(stage, str) or stage not in implementations or stage != path.stem:
raise ResultError("impl_invalid", f"{path}: stage must be a known stage matching the filename")
implementations[stage] = implementation
Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/server/result/compose.py
Line: 374

Comment:
**A stand-in can disappear**

The reader trusts `stage` without checking that it matches the filename or belongs to `StageName`. An `objects.json` marker naming `reads` as a stand-in can be overwritten by a later `reads.json` marker naming it real. The internal record and reviewer page then hide that stand-in.

Reject unknown or mismatched stage names with `impl_invalid`, and add a test for conflicting markers.

```suggestion
            stage = doc.get("stage")
            if not isinstance(stage, str) or stage not in implementations or stage != path.stem:
                raise ResultError("impl_invalid", f"{path}: stage must be a known stage matching the filename")
            implementations[stage] = implementation
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex Fix in Claude Code

Comment on lines +372 to +373
if implementation not in {"real", "stand-in"}:
raise ResultError("impl_invalid", f"{path}: implementation is neither real nor stand-in")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Bad markers lose useful errors

A marker containing "implementation": [] or an object raises TypeError at this set-membership check. It never reaches ResultError("impl_invalid", ...), so the failure loses both the marker filename and the promised error code. This makes the failed run harder to diagnose.

Check that implementation is a string before testing its value, and cover arrays and objects in the tests.

Suggested change
if implementation not in {"real", "stand-in"}:
raise ResultError("impl_invalid", f"{path}: implementation is neither real nor stand-in")
if not isinstance(implementation, str) or implementation not in {"real", "stand-in"}:
raise ResultError("impl_invalid", f"{path}: implementation is neither real nor stand-in")
Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/server/result/compose.py
Line: 372-373

Comment:
**Bad markers lose useful errors**

A marker containing `"implementation": []` or an object raises `TypeError` at this set-membership check. It never reaches `ResultError("impl_invalid", ...)`, so the failure loses both the marker filename and the promised error code. This makes the failed run harder to diagnose.

Check that `implementation` is a string before testing its value, and cover arrays and objects in the tests.

```suggestion
            if not isinstance(implementation, str) or implementation not in {"real", "stand-in"}:
                raise ResultError("impl_invalid", f"{path}: implementation is neither real nor stand-in")
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex Fix in Claude Code

This branch has not been deployed

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

Labels

size:M 30-99 effective changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant