Skip to content

feat(hostd): replace per-price pin toggles with a single switch - #1539

Open
telestrial wants to merge 1 commit into
mainfrom
09-11-feat_hostd_replace_per-price_pin_toggles_with_a_single_switch
Open

feat(hostd): replace per-price pin toggles with a single switch#1539
telestrial wants to merge 1 commit into
mainfrom
09-11-feat_hostd_replace_per-price_pin_toggles_with_a_single_switch

Conversation

@telestrial

@telestrial telestrial commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Screenshot 2026-09-11 at 4.47.56 PM.png

This PR changes hostd's configuration page to support either pinning all pinnable fields or none of them, while still respecting the legacy mixed configuration. After this PR, it will not be possible through the UI to set a new mixed configuration. I think it's still possible to set a mixed config through the API, though?

Single field pinning toggles are gone. If you're in that legacy state, the overall pin toggle is set to the off position. I wrestled with that and can see arguments for having it in the on position. I'm open to whatever we think is best.

I tested this on my own host without saving anything and used clusterd beyond that, so more manual testing on a real hostd daemon would be useful before we release this into the wild.

@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hostd Ready Ready Preview Sep 11, 2026 9:59pm UTC
4 Skipped Deployments
Project Deployment Actions Updated
explorer Ignored Ignored Preview Sep 11, 2026 9:59pm UTC
explorer-zen Ignored Ignored Preview Sep 11, 2026 9:59pm UTC
indexd Ignored Ignored Preview Sep 11, 2026 9:59pm UTC
renterd Ignored Ignored Preview Sep 11, 2026 9:59pm UTC

Request Review

@changeset-bot

changeset-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b1baabe

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
hostd Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@telestrial
telestrial marked this pull request as ready for review September 11, 2026 21:39
Copilot AI lite review requested due to automatic review settings September 11, 2026 21:39

@claude claude 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.

Claude Code Review

Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.

Tip: disable this comment in your organization's Code Review settings.

Copilot AI 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.

🟡 Changes recommended

Resolve mixed-state save behavior, pinning-disabled UI handling, effective-state validation, and Save availability for explicit unpinning.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This PR replaces hostd’s per-price pin toggles with a single all-or-nothing switch while preserving legacy mixed configurations.

Changes:

  • Updates pinning transforms, UI, validation, and save-state handling.
  • Adds mixed-pinning notices and interaction tracking.
  • Adds unit/E2E coverage, fixtures, and a changeset.
File summaries
File Summary
libs/e2e/src/fixtures/textInput.ts Adds visibility assertions.
apps/hostd/contexts/config/usePinningTouched.tsx Tracks explicit pinning changes.
apps/hostd/contexts/config/useOnValid.tsx Handles pinning save behavior.
apps/hostd/contexts/config/types.ts Defines pinning state types.
apps/hostd/contexts/config/transform.ts Transforms aggregate and legacy pinning states.
apps/hostd/contexts/config/transform.spec.ts Tests transform behavior.
apps/hostd/contexts/config/index.tsx Exposes legacy pinning state.
apps/hostd/contexts/config/fields.tsx Updates pricing fields and validation.
apps/hostd/components/Config/PricingSetting.tsx Adds shared pricing controls and notices.
apps/hostd/components/Config/index.tsx Renders unified pricing controls.
apps/hostd-e2e/src/specs/configLegacyPinning.spec.ts Tests legacy mixed configurations.
apps/hostd-e2e/src/specs/config.spec.ts Updates pricing configuration tests.
apps/hostd-e2e/src/fixtures/configSetMixedPinning.ts Provides mixed-pinning setup.
apps/hostd-e2e/src/fixtures/configResetAllSettings.ts Updates configuration reset behavior.
.changeset/pin-all-prices-or-none.md Documents the user-facing change.
Review details

Suppressed comments (6)

apps/hostd/contexts/config/fields.tsx:264

  • In the mixed legacy state, this fiat input is rendered for a pinned storage price while values.shouldPinPrices is false. The short-circuit therefore accepts a negative pinned value and transformUpSettingsPinned can send it in the preserved mixed payload; validate against the effective per-price pin state instead (and apply the same correction to the other pinned-price validators).
              !values.shouldPinPrices ||

apps/hostd/contexts/config/fields.tsx:313

  • In the mixed legacy state, this fiat input is rendered for a pinned egress price while values.shouldPinPrices is false. The short-circuit therefore accepts a negative pinned value and transformUpSettingsPinned can send it in the preserved mixed payload; validate against the effective per-price pin state instead.
              !values.shouldPinPrices ||

apps/hostd/contexts/config/fields.tsx:361

  • In the mixed legacy state, this fiat input is rendered for a pinned ingress price while values.shouldPinPrices is false. The short-circuit therefore accepts a negative pinned value and transformUpSettingsPinned can send it in the preserved mixed payload; validate against the effective per-price pin state instead.
              !values.shouldPinPrices ||

apps/hostd/contexts/config/fields.tsx:426

  • In the mixed legacy state, this fiat input is rendered for a pinned max-collateral value while values.shouldPinPrices is false. The short-circuit therefore accepts a negative pinned value and transformUpSettingsPinned can send it in the preserved mixed payload; validate against the effective per-price pin state instead.
              !values.shouldPinPrices ||

apps/hostd/contexts/config/index.tsx:78

  • This notice is derived from the pinned response without checking pinningEnabled. Since the pinned resource is requested even when the explorer feature is disabled, a disabled host with a legacy mixed response can see an alert telling it to change pinning while shouldPinPrices itself is hidden. Include pinningEnabled in this condition so the notice is only shown when the host can act on it.
  const showMixedPinningNotice = hasMixedPinning && !pinningTouched

apps/hostd/contexts/config/usePinningTouched.tsx:24

  • Tracking touched state here is not enough to make the all-unpinned resolution savable. ConfigActions still disables Save when form.formState.isDirty is false; toggling a legacy mixed switch false → true → false marks this field touched but restores its default value, so isDirty becomes false. With no other edit, the host cannot submit the deliberate choice and the mixed configuration remains. Expose pinningTouched through the config context and include it in the save-enabled condition (or otherwise mark this action dirty).
    pinningTouched: !!touchedFields.shouldPinPrices,
  • Files reviewed: 15/15 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/hostd/components/Config/PricingSetting.tsx Outdated
Comment thread apps/hostd/components/Config/index.tsx Outdated
@telestrial
telestrial force-pushed the 09-11-feat_hostd_replace_per-price_pin_toggles_with_a_single_switch branch from 2a8f7b5 to b1baabe Compare September 11, 2026 21:58
Copilot AI review requested due to automatic review settings September 11, 2026 21:58

Copilot AI 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.

🔵 Needs a closer look

Mixed legacy pin validation and pinning-change tracking need correction before approval.

Review details

Suppressed comments (6)

apps/hostd/contexts/config/fields.tsx:264

  • For a mixed legacy host, transformDown sets shouldPinPrices to false even when this storage fiat input is still shown as pinned. This condition therefore short-circuits the non-negative check, allowing a negative value to be submitted for an active pinned price. Validate against the effective per-price pin state, including the legacy state, rather than only the aggregate switch.
              !values.shouldPinPrices ||

apps/hostd/contexts/config/fields.tsx:313

  • For a mixed legacy host, transformDown sets shouldPinPrices to false even when this egress fiat input is still shown as pinned. This condition therefore short-circuits the non-negative check, allowing a negative value to be submitted for an active pinned price. Validate against the effective per-price pin state, including the legacy state, rather than only the aggregate switch.
              !values.shouldPinPrices ||

apps/hostd/contexts/config/fields.tsx:361

  • For a mixed legacy host, transformDown sets shouldPinPrices to false even when this ingress fiat input is still shown as pinned. This condition therefore short-circuits the non-negative check, allowing a negative value to be submitted for an active pinned price. Validate against the effective per-price pin state, including the legacy state, rather than only the aggregate switch.
              !values.shouldPinPrices ||

apps/hostd/contexts/config/fields.tsx:426

  • For a mixed legacy host, transformDown sets shouldPinPrices to false even when this max-collateral fiat input is still shown as pinned. This condition therefore short-circuits the non-negative check, allowing a negative value to be submitted for an active pinned price. Validate against the effective per-price pin state, including the legacy state, rather than only the aggregate switch.
              !values.shouldPinPrices ||

apps/hostd/contexts/config/transform.ts:313

  • For a mixed legacy host, transformDown deliberately sets shouldPinPrices to false, but the pinned fiat inputs for the individually pinned prices are still displayed. The range validators in fields.tsx now key off this aggregate flag, so a negative value entered into a displayed legacy-pinned field passes validation and is sent back with pinned: true; validate against the effective per-price pin state instead of the aggregate switch.
          shouldPinPrices:
            settingsPinned.storage.pinned &&
            settingsPinned.egress.pinned &&
            settingsPinned.ingress.pinned &&
            settingsPinned.maxCollateral.pinned,

apps/hostd/contexts/config/usePinningTouched.tsx:24

  • This treats a field blur as an explicit pinning change. FieldSwitch passes its onBlur into React Hook Form, so a user who merely tabs through the switch sets touchedFields.shouldPinPrices and the next unrelated save resolves a mixed configuration even though the switch value never changed. Track an actual checked-value change separately while retaining the on/off/on case.
    pinningTouched: !!touchedFields.shouldPinPrices,
  • Files reviewed: 15/15 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants