Skip to content

Setup owns its flow and questions, tested in-process behind a seam - #412

Merged
JacobStephens2 merged 2 commits into
mainfrom
issue-411
Oct 5, 2026
Merged

JacobStephens2 merged 2 commits into
mainfrom
issue-411

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

Setup now has its own module. Its rules sit in front of a private Outside seam. The User config module keeps parsing, loading, the defaults and completing.

 src/
 ├── config.rs           # parse, load, DEFAULTS, complete, home and path
-│                       #   + Setup flow, writing answers, suggested address
-├── questions.rs        # Setup's questions, on the terminal directly
+├── setup.rs            # setup() and offer(): the flow, writing answers, suggested address
+│                       #   trait Outside: OnMachine (real), Scripted (tests)
+└── setup/
+    └── questions.rs    # the questions, asked through Outside
setup() / offer()                 # same two entry points, no arguments
  OnMachine::new(home)            # terminal, echo-off, claude test call, codex catalog,
                                  # Credentials, gh, git, User config file, Resend
  run_setup / run_offer(outside)  # rules: re-ask loops, Harness default, Codex settling,
                                  # noreply filter, write order, the offer's warnings

Evidence

  • Before: about 70 pseudo-terminal end-to-end tests across tests/setup.rs (56) and tests/setup_offer.rs (14) were the only way to check a Setup rule.
    After: 59 in-process tests in src/setup.rs drive Setup through Scripted. That adapter checks each prompt in order and records every line said and every write, save and send. The end-to-end suites keep only the 16 tests for wiring and the real terminal that the issue lists. cargo test passes in full, and cargo clippy --all-targets is clean.
Scripted::answering([(OFFER,"y"), …, (KEY_PROMPT, KEY), (TEST_EMAIL,"y")])
offer() effects == [WriteNew, Step("wrote the User config …"), SaveKey(KEY),
                    Step("wrote the Credentials …"), SendTest{to: me@example.com}, Step(SENT)]

Two rules from deleted end-to-end tests live outside Setup, so they moved to unit tests in the module that owns them:

  • every default key carries a comment giving its default (config.rs);
  • a key is saved into existing Credentials in place (resend_key.rs).

Merge Danger

Door: two-way

This is a refactor with no change to prompts, lines, files or exit codes, so a revert is clean.

Blast Radius: Setup

The risk is a behaviour drift on a real terminal that the deleted end-to-end tests would have caught. The kept tests cover Ctrl-C, hidden key input, Enter throughout, and the offer's wiring into a Run.

Unaddressed findings

Standards

  • Outside is wide (16 methods); read/read_hidden, say/step and the two User config reads could merge. Skipped: the issue lists these exact methods, and it keeps hidden input as its own method on purpose.
  • Feature Envy: set/set_email_to use config's TOML helpers, which became pub. Skipped: the issue says writing the answers, setting a key in place and setting email.to move to Setup, while completing stays in config.
  • E2E with_no_terminal_and_no_user_config_setup_writes_the_defaults and on_a_terminal_pressing_enter_throughout… duplicate in-process names. Skipped: the issue's keep list names both. Each checks the real file and terminal, not only the rule.
  • questions calls the parent's suggested_address. Skipped: the lookup must stay lazy, made only when notifications are on and there is no email.to. A child module using its parent's private helper is ordinary in Rust.
  • Scripted uses &'static str for scripted failures. Skipped: this is test-only and matches the other scripted adapters.

Spec

  • Claude's test call prints "checking the Model … with a test call" through progress::step, not Outside::step. Skipped: the real adapter makes the call "as the code does today" through Choice::test_call, which a Run shares. The line is unchanged.
  • No in-process check that the test email uses the key just entered. Skipped: the scripted adapter covers the order (save, then send). The key reaching Resend is the real adapter reading the Credentials, which is not a Setup rule.

Closes #411

🤖 Generated with Claude Code

JacobStephens2 and others added 2 commits October 5, 2026 04:02
)

A new Setup module owns Setup end to end: `setup` and the first Run's
offer, the questions as a private child, and the helpers that write the
answers into the User config. Everything it does outside itself goes
through a private `Outside` seam, with a real adapter on the machine and
a scripted one in tests. The User config module keeps parsing, loading,
the defaults and completing.

The Setup rules are now tested in-process, and the end-to-end Setup and
Setup-offer tests they cover are deleted, keeping only those for the
wiring into a Run and the command line, and the real terminal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and its offer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JacobStephens2
JacobStephens2 merged commit 5efa828 into main Oct 5, 2026
13 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-411 branch October 5, 2026 08:12
@JacobStephens2 JacobStephens2 mentioned this pull request Oct 5, 2026
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.

Setup owns its flow and questions, tested in-process behind a seam

1 participant