Contact-details profile schema + wizard + Filler.profile arg (bd-ic1 Phase 1) - #65
Merged
Merged
Conversation
…ofile Adds the optional ContactDetails sub-model on Profile so kleinanzeigen- style contact forms can be filled from a single source of truth. All eight fields are independently optional — every existing profile loads unchanged. - Profile.contact_details: anrede, given_name, surname, phone, street, plz, schufa_status, household_type (each None by default). - profile.example.json gets the block with every value set to null. - Wizard adds a 'Kleinanzeigen contact details (optional)' section that's gated behind a Confirm prompt; blank answers stay None. - Filler protocol now accepts profile=None as a kw-only argument. Both existing fillers take and ignore it; apply.py threads the loaded Profile into every filler.fill() call site. Phase 1 ships the additive infrastructure only. The kleinanzeigen filler still relies on account-prefill for structured fields; the actual iterate-and-fill work is tracked separately as a follow-up bead so it can land alongside empirical capture of the live form's HTML.
There was a problem hiding this comment.
Pull request overview
This PR lays the Phase 1 groundwork for future Kleinanzeigen structured contact-form filling by adding profile.contact_details, prompting for it in the init wizard, and threading a profile object through the filler API and apply orchestration.
Changes:
- Added
ContactDetailssub-model toProfile(plus example JSON) and corresponding schema tests. - Extended
flatpilot initwizard to optionally collect Kleinanzeigen contact details (with tests). - Extended the
Filler.fill()protocol with a kw-onlyprofileargument and threaded the loadedProfilethroughapply_to_flat(); updated fillers and apply-related tests accordingly.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/flatpilot/profile.py |
Introduces ContactDetails model and adds Profile.contact_details. |
src/flatpilot/profile.example.json |
Adds contact_details block to the shipped example profile. |
src/flatpilot/wizard/init.py |
Adds optional wizard section + prompt loop to collect contact details. |
src/flatpilot/fillers/base.py |
Extends filler protocol with `profile: Profile |
src/flatpilot/fillers/kleinanzeigen.py |
Accepts new profile kwarg (currently unused) for forward compatibility. |
src/flatpilot/fillers/wg_gesucht.py |
Accepts new profile kwarg (ignored) for protocol compatibility. |
src/flatpilot/apply.py |
Threads loaded Profile through to filler.fill() (dry-run + submit). |
tests/test_contact_details_schema.py |
Adds validation and example-load coverage for ContactDetails. |
tests/test_wizard_contact_details.py |
Adds unit tests for the contact-details wizard prompt loop. |
tests/test_apply_orchestrator.py |
Updates filler stub + asserts apply orchestrator passes a Profile to the filler. |
tests/test_apply_lock.py |
Updates filler fakes to accept new profile kwarg. |
.beads/issues.jsonl |
Updates beads tracking entries related to ic1/ko1 follow-ups and repo memories. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
60
to
63
| SubmitVerificationError, | ||
| ) | ||
| from flatpilot.profile import Profile | ||
| from flatpilot.scrapers.kleinanzeigen import CONSENT_SELECTORS, HOST, WARMUP_URL |
Comment on lines
229
to
234
| exclude_short_term: bool = True | ||
|
|
||
| wbs: WBS = Field(default_factory=WBS) | ||
| contact_details: ContactDetails = Field(default_factory=ContactDetails) | ||
| notifications: Notifications = Field(default_factory=Notifications) | ||
| attachments: Attachments = Field(default_factory=Attachments) |
|
|
||
|
|
||
| def _prompt_optional_str(out: Console, prompt: str, *, default: str) -> str | None: | ||
| raw = Prompt.ask(prompt, default=default) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 1 of bd-ic1: additive groundwork so a future kleinanzeigen filler can fill structured contact-form fields (Anrede, Vorname, etc.) from
profile.contact_details. The actual iterate-and-fill work is filed as a follow-up bead — it needs empirical capture of the live kleinanzeigen contact-form HTML to pick selectors against, which we don't have yet.What's in this PR:
Profile.contact_details— new optionalContactDetailssub-model with eight fields:anrede(frau/herr/divers/keine_angabe),given_name,surname,phone,street,plz,schufa_status(available/no/on_request),household_type(single/couple/family/wg/other). Each is independently optional and defaults toNone.profile.example.jsongets the block with every value null. Every existing profile loads unchanged.Filler.fillprotocol now acceptsprofile: Profile | None = Noneas a kw-only argument. Both existing fillers (kleinanzeigen, wg-gesucht) take and ignore it.apply.pythreads the loaded Profile into everyfiller.fill()call site — both dry-run and live.What's NOT in this PR (follow-up bead)
The actual kleinanzeigen filler logic that iterates form fields and fills them from
profile.contact_details. That work needs empirical capture of the live form's HTML in two variants (full 15-field, message-only) before selectors can be picked. Filed as a P3 follow-up.Test plan
pytest— 575/575 pass, coverage 80%.ruff checkon touched files — clean.tests/test_contact_details_schema.pycovers defaults, full payload, unknown-field rejection, invalid enums, andProfile.load_example()round-trip.tests/test_wizard_contact_details.pycovers the Confirm-gate skip path, all-blank → all-None, and a full answer-set round-trip.profilekwarg and assertsapply_to_flatpasses aProfileinstance through to the filler.