Community resource sharing platform

Sharehood

Less buying, more belonging

Sharehood turns neighborhoods into organized, trustworthy lending libraries for urban residents and HOA/tenant organizers. List tools and gear once, then neighbors book through a live calendar with smart pickup windows that auto-adjust for overlaps; Stripe deposit holds curb no-shows. Borrowing takes minutes, not days, cutting household spend 35%, reducing clutter, and saving organizers five hours a month.

Subscribe to get amazing product ideas like this one delivered daily to your inbox!

Sharehood

Product Details

Explore this AI-generated product idea in detail. Each aspect has been thoughtfully created to inspire your next venture.

Vision & Mission

Vision
Power neighborhoods worldwide to share what they own, cutting consumption and costs while strengthening trust and local resilience.
Long Term Goal
Within four years, activate 25,000 neighborhoods worldwide sharing one million items monthly, cutting household spend 35% and local consumption 20%, while increasing neighbor trust and participation scores by 25%.
Impact
Sharehood cuts household spend on infrequent-use items by 35% and boosts neighborhood reuse 60% in three months. Urban residents get borrow turnaround from days to minutes and 70% fewer no-shows, while HOA/tenant organizers save 5 hours monthly by eliminating group‑chat coordination.

Problem & Solution

Problem Statement
Urban residents and HOA/tenant organizers struggle to borrow and lend everyday tools locally: requests scatter across group chats, schedules collide, and tracking fails. Spreadsheets are tedious, while rental marketplaces feel impersonal, costly, and risky for simple neighborhood borrowing.
Solution Overview
Sharehood replaces group-chat borrowing chaos with a single neighborhood lending hub where items become bookable listings with clear availability. A live reservation calendar with auto-adjusting pickup windows and Stripe-backed deposit holds coordinates overlapping requests and enforces accountability, turning requests from days of back-and-forth into minutes.

Details & Audience

Description
Sharehood is a lightweight platform that turns neighborhoods into organized, trustworthy lending libraries. Built for urban adults, HOA leaders, and community organizers who share tools, gear, and party supplies. It cuts household spend, reduces clutter, and replaces group-chat chaos with fast, local borrowing. Distinctive feature: a live reservation calendar with smart pickup windows that auto-adjust for overlapping requests.
Target Audience
Urban residents and tenant/HOA organizers (25-55) seeking savings and decluttering, actively coordinating neighbors through apps.
Inspiration
At 5:12 p.m., our block chat lit up with a simple ask: anyone have a ladder? By 6, there were 30 pings, two overlapping pickups, a wrong porch, and a lost number. The owner gave up; the party lights went up at 10. Watching generosity derail on logistics, I sketched Sharehood: bookable listings, a live calendar, smart pickup windows, and deposit holds—saying yes without chaos.

User Personas

Detailed profiles of the target users who would benefit most from this product.

N

New-Neighbor Networker Nate

- Age 29, moved within last 60 days to mid-rise near downtown. - Works hybrid marketing analyst; income $78k; prioritizes walkable errands. - Lives with partner; no car; relies on public transit and bikes. - Uses iPhone; heavy on Nextdoor, WhatsApp, and Instagram for local info. - Rents a one-bedroom; building has secure package room and lobby.

Background

Moved for a new role and downsized, leaving bulky gear behind. Previously organized campus swap meets, so he sees sharing as both utility and community glue. Early attempts using classifieds felt sketchy and slow.

Needs & Pain Points

Needs

1. Fast onboarding with verified local profiles. 2. Clear pickup windows matching work hours. 3. Light icebreakers to spark neighbor connections.

Pain Points

1. Anonymous buildings feel isolating and unsafe. 2. Unreliable pickups waste evenings. 3. Coordination lost in scattered DMs.

Psychographics

- Seeks belonging through practical, low-friction exchanges. - Values transparency, verified identities, and punctuality. - Enjoys meeting neighbors with clear boundaries. - Curious early adopter of community tech.

Channels

1. Nextdoor - new resident threads 2. WhatsApp - building chat 3. Instagram - neighborhood hashtags 4. Facebook Groups - local community 5. TikTok - city micro-creators

M

Micro-Workshop Maker Maya

- Age 31, product designer at hardware startup; income $105k. - Rents a 400 sq ft studio; storage limited to one closet. - Commutes by bike; weekends at community makerspace and shared workshop. - Uses Android; active on Instagram, YouTube, and Reddit maker forums. - Buys consumables locally; borrows specialty tools to prototype quickly.

Background

Built robots in high school and led a university makerspace. After downsizing to afford city life, she shed bulky tools but kept ambitious projects. Early rentals felt slow and unreliable, stalling iteration.

Needs & Pain Points

Needs

1. Accurate condition photos and specs. 2. Flexible evening pickups near transit. 3. Reliable availability to chain tasks.

Pain Points

1. Single-use tools clog precious space. 2. Missing parts derail builds. 3. Cancellations break prototype momentum.

Psychographics

- Precision over abundance; hates clutter. - Thrives on rapid, iterative building. - Values shared knowledge and mutual respect. - Prefers clear instructions and documented condition.

Channels

1. Reddit - r/makers, r/DIY 2. YouTube - tool reviews 3. Instagram - build reels 4. Discord - maker servers 5. Nextdoor - gear swap posts

Y

Yield-Driven Lister Yara

- Age 38, operations analyst in logistics; income $120k; data-savvy. - Owns a two-bedroom condo; gear closet and basement storage cage. - Tech-forward: iOS, smart locks, Wi‑Fi cameras, spreadsheets for everything. - Time-blocks weekends; prefers automation over messaging back-and-forth. - Previously monetized a spare room; now optimizes gear utilization metrics.

Background

Cut teeth streamlining warehouse workflows, then applied those habits to household assets. After lending ad hoc to neighbors, she tired of manual coordination and inconsistent expectations. Seeks predictable, low-effort circulation with clear safeguards.

Needs & Pain Points

Needs

1. Demand heatmaps by item and time. 2. Deposit recommendations by risk profile. 3. Automated recurring availability templates.

Pain Points

1. No-shows break utilization targets. 2. Fragile items returned undocumented. 3. High-touch messaging drains weekends.

Psychographics

- Optimization thrills; waste frustrates deeply. - Trusts data over anecdotes. - Risk-managed generosity, not careless charity. - Prefers automation with transparent controls.

Channels

1. LinkedIn - operations communities 2. Substack - optimization newsletters 3. X/Twitter - data threads 4. Reddit - r/BuyItForLife 5. Nextdoor - local demand pings

O

Off-Hours Borrower Owen

- Age 33, ICU nurse on rotating nights; income $96k. - Rents near hospital; sleeps days with blackout curtains. - No car; late-night walking radius is five blocks. - iPhone, Apple Watch; silences notifications during sleep. - Shops 24/7 grocers; seeks services with true overnight options.

Background

Shift work wrecked previous booking attempts with daytime-only pickups. After missed handoffs cost him overtime pay, he demands flexible, reliable windows. Uses routines to protect scarce rest.

Needs & Pain Points

Needs

1. Overnight pickup windows guaranteed. 2. Quiet reminders respecting do-not-disturb. 3. Easy extensions when shifts overrun.

Pain Points

1. Daytime-only availability blocks access. 2. Late lenders steal sleep. 3. Chat pings disrupt recovery.

Psychographics

- Sleep-first, fiercely guards downtime. - Reliability beats bargains every time. - Low chatter, high clarity communicator. - Values safety and well-lit access.

Channels

1. WhatsApp - shift crew chat 2. Reddit - r/nursing 3. TikTok - nightshift hacks 4. Google Maps - open now 5. Sharehood - push alerts

B

Block-Party Planner Ben

- Age 41, nonprofit program manager; stipends events for neighborhood association. - Lives in rowhouse near closed-street corridor; permits often required. - Weekends devoted to community events; weekday evenings for planning. - Uses laptop-first workflow; Google Sheets, Canva, and Slack. - Coordinates volunteers across three blocks; storage limited to one shed.

Background

Started with potluck stoops, grew into monthly street fairs. Burned by double-booked tables and missing PA systems, he systematized everything. Needs ironclad scheduling across multiple owners.

Needs & Pain Points

Needs

1. Multi-item bookings in one checkout. 2. Deposit holds to ensure returns. 3. Printable pickup and return timelines.

Pain Points

1. Double-bookings tank event flow. 2. Scattered chats across owners. 3. Missing handoff confirmations.

Psychographics

- Community-first, logistics-obsessed organizer. - Hates chaos; worships checklists. - Demands visible accountability and receipts. - Celebrates small wins publicly.

Channels

1. Eventbrite - organizer tools 2. Facebook Groups - volunteers 3. Slack - neighborhood workspace 4. Nextdoor - event posts 5. Mailchimp - community newsletter

B

Budget-Balancing Parent Priya

- Age 37, project manager; household income $150k; two kids under 8. - Lives in two-bedroom near transit; tight storage. - Manages family logistics in Google Calendar; color-coded. - Active in PTA; WhatsApp class chats daily. - Prefers pickup near school, daycare, or playground.

Background

Overspent on baby gear that gathered dust, then discovered sharing groups. Now orchestrates activities tightly around bedtime and school runs. Needs reliability more than bargains.

Needs & Pain Points

Needs

1. Safety badges and cleanliness notes. 2. Precise windows around school runs. 3. Auto-sync with family calendar.

Pain Points

1. Weekend stockouts ruin plans. 2. Late pickups wreck bedtime. 3. Unclear sanitation standards.

Psychographics

- Frugal, quality-over-quantity decision-maker. - Schedules life in 30-minute blocks. - Trusts recommendations from other parents. - Safety and cleanliness are non-negotiable.

Channels

1. WhatsApp - class parent chat 2. Facebook Groups - local parents 3. Instagram - neighborhood parents 4. Google Calendar - shared family 5. Nextdoor - kid gear posts

Product Features

Key capabilities that make this product valuable to its target users.

Trust Tiers

Clear, color‑coded levels earned by ID checks, on‑time handoffs, and solid vouches. Lenders can set a minimum tier per item; higher tiers unlock lower deposits, instant approvals, and access to premium gear—giving cautious newcomers a visible path to trust while boosting lender confidence.

Requirements

ID Verification & Proofing
"As a cautious borrower, I want to verify my identity quickly so that I can earn initial trust and access items with fewer hurdles."
Description

Implement a secure identity verification flow that validates government ID, selfie liveness, and address to establish baseline trust. Integrate with a third‑party KYC provider (e.g., Stripe Identity/Persona) via API, handle retries and edge cases, and persist only verification status and metadata (not raw PII) per privacy policy. Expose verification state to the Trust Tiers engine, trigger onboarding prompts for unverified users, and provide clear, localized UI guidance and progress indicators. Emit events on verification success/failure for auditing and tier recalculation, and support manual review fallback for exceptions. Ensure accessibility, mobile camera compatibility, and compliance with applicable data protection regulations.

Acceptance Criteria
First-Time Booking Triggers ID Verification
Given an unverified user attempts to book an item that requires a minimum trust tier dependent on ID verification When the user proceeds to checkout Then the system blocks checkout and launches the KYC flow via the configured provider And the UI shows localized guidance and a step-by-step progress indicator And the user cannot complete booking until verification status becomes "verified" or the item’s minimum tier requirement is removed by the lender When the user successfully completes verification Then the user is returned to checkout within 3 seconds and can complete booking without re-entering details
Successful KYC Verification Persists Minimal Metadata
Given the KYC provider returns a successful verification including government ID, selfie liveness, and address checks When the provider callback webhook is received Then the system persists only: verification_status=verified, provider_name, verification_id, timestamp, checks_passed, review_type (auto/manual), and country_code And raw PII artifacts (ID images, full address strings, biometric templates) are not stored in application databases or logs And stored metadata is encrypted at rest and masked in operational logs And an audit event "verification.succeeded" is emitted with non-PII metadata and a trace_id
Retry and Edge-Case Handling in KYC Flow
Given a user experiences a capture failure, poor lighting, or timeout during KYC When the provider returns a retryable error Then the UI offers up to 3 retries per session with actionable, localized tips And the verification session can be resumed within 24 hours via a secure deep link without restarting checkout When the retry limit is exceeded or an unretryable error occurs Then the case transitions to needs_manual_review and the user is notified of the expected review SLA
Manual Review Queue for Exceptions
Given a verification outcome of needs_manual_review or a contested failure When the case is created Then it appears in the reviewer queue with redacted PII and essential metadata (provider_name, verification_id, reasons, timestamps) And reviewers can Approve or Reject with required notes And the decision updates the user’s verification status accordingly and emits a "verification.reviewed" event And the user receives a localized notification of the decision; SLA target for first response is under 24 hours
Accessible, Mobile-Ready Verification UI and Compliance
Given users on modern mobile devices and assistive technologies When they perform the verification flow Then the UI conforms to WCAG 2.1 AA for contrast, focus order, labels, and screen-reader announcements of step progress And camera capture works on Safari iOS 16+ and Chrome/Edge Android 12+ on popular mid-tier devices, with fallback to document upload if camera permissions are denied And all user-facing copy is localized with keys for at least en, es, and fr and auto-selected by browser locale And explicit consent for data processing is presented and recorded before starting KYC, with links to provider privacy notices
Trust Tier Recalculation and Eventing on Verification Change
Given a user’s verification status transitions (succeeded, failed, reviewed) When the system processes the provider webhook or a manual decision Then the Trust Tiers engine recalculates the user’s tier within 5 seconds And booking eligibility rules and deposit amounts reflect the new tier immediately And domain events "verification.succeeded", "verification.failed", and "verification.reviewed" are emitted to the event bus with idempotency keys and delivery is logged
Data Minimization, Retention, and Security Controls
Given the system handles verification outcomes and metadata When storing, querying, and logging verification data Then no raw PII from KYC (images, full addresses, biometrics) is persisted or logged by Sharehood services And verification metadata is retained only as long as necessary for trust tiering and auditing per policy, and is deleted upon account deletion or DSR And all at-rest metadata is encrypted and all access is audited with least-privilege roles
Real‑time Trust Scoring Engine
"As a lender, I want an objective, transparent trust score so that I can confidently decide who can borrow my items."
Description

Create an event‑driven scoring service that calculates a user’s Trust Tier from weighted signals: ID verification, on‑time pickups/returns, no‑show rate, deposit holds/releases, dispute outcomes, damage claims, successful bookings, tenure, and peer vouches. Define configurable weights, decay over time, and anti‑gaming safeguards. Map aggregate scores to color‑coded tiers with clear thresholds and versioned policies. Provide explainability by returning top contributing factors for UI display. Support real‑time updates on transaction events and nightly backfills, with APIs for read (current tier, score, rationale) and write (admin adjustments, appeals outcomes). Log all computations for auditability and enable A/B testing of weight configurations.

Acceptance Criteria
Real-time recalculation on transaction events
Given a supported trust signal event (ID_verified, booking_created, pickup_marked_on_time/late, return_marked_on_time/late, no_show_reported, deposit_hold_placed/released, dispute_opened/resolved, damage_claim_filed/resolved, vouch_submitted/withdrawn) When the event is received by the scoring engine Then the user's trust score is recalculated using the active policy_version within 200ms compute time (p95) and 1s end-to-end propagation to the read API And the updated score and tier are persisted and available via the read API And processing is idempotent per event_id and user_id; duplicate deliveries do not change the resulting score/tier more than once And events are applied in event_timestamp order; ties are resolved deterministically by event_id And a tier_changed event is emitted only if the tier actually changes
Policy configuration, decay, and versioning with A/B cohorts
Given an admin publishes a new weights/decay configuration as policy_version vN When vN is activated Then all subsequent computations reference vN and include policy_version and weights_hash in responses and audit logs And per-signal weights and half-life decay (days) are validated (weights within configured bounds; half-life > 0) And policies can be rolled back to a prior version without service restart; effect is visible in new computations within 60 seconds And A/B cohorts are assigned via stable hashing of user_id and experiment_id; cohort assignment is consistent across sessions and included as cohort_id in outputs And multiple policy_versions may be active in parallel across cohorts with no cross-contamination And a dry-run endpoint returns expected score/tier for a supplied user snapshot under any policy_version
Tier mapping with thresholds and color codes
Given an aggregate numeric trust score is produced When mapping the score to a tier Then the tier is derived from configurable, versioned thresholds with explicit boundaries (lower_bound inclusive, upper_bound exclusive) And mapping is deterministic and monotonic: increasing score never lowers the tier And the tier object includes: tier_code, color_hex, label, threshold_range, previous_tier, effective_at And boundary tests at each threshold ±0.01 return the expected tier
Explainability in read API responses
Given a read API request for a user's trust profile When the response is returned Then it includes: current_score, current_tier, policy_version, cohort_id, and the top 5 contributing factors And each factor includes signal_name, direction (+/-), absolute_contribution, normalized_share_percent; the sum of normalized_share_percent across factors is 100% ±1% And the response lists up to 10 recent score-impacting events within the last 30 days with event_type and timestamp And no PII (e.g., ID document details) is exposed; only user_id and generic signal names are returned And identical inputs produce identical rationale payloads (deterministic output)
Computation audit logging and reproducibility
Given any score computation occurs (real-time or batch) When the computation completes Then an immutable audit record is written containing: user_id; event_id or job_run_id; event_type; inputs_snapshot_hash; signals vector with timestamps; previous_score/tier; new_score/tier; policy_version; weights_hash; cohort_id; idempotency_key; request_id/trace_id; started_at; completed_at; compute_ms; outcome; and error_details if any And logs are retained for at least 13 months and are queryable by user_id and event_id within 60 seconds of write And replaying the recorded inputs under the same policy_version reproduces the same score within ±0.01 absolute difference
Admin adjustments and appeals write APIs
Given an authorized admin submits a write API request to apply an adjustment or record an appeal outcome for a user When the request includes reason_code, magnitude (delta or flag), effective_at, optional expiry, and idempotency_key Then RBAC and schema validation pass, an immutable adjustment entry is persisted, the score is recalculated within 1s, and the response returns adjustment_id, new_score, and new_tier And duplicate requests with the same idempotency_key are deduplicated safely And reversals are performed by creating compensating adjustments; original entries are never edited or deleted And all adjustments appear in audit logs and as explainability factors labeled admin_adjustment or appeal_outcome
Nightly backfill and score decay recomputation
Given a nightly backfill window is configured When the batch job runs Then it recomputes scores for all active users applying time-decay as of batch_time using the active policy_version per cohort And it processes at least 10,000 users per minute with p95 compute_ms per user < 150ms And the job is idempotent and supports resume-on-failure from the last successful checkpoint And after completion, the read API reflects recomputed scores within 5 minutes And any discrepancy versus a real-time recomputation at the same timestamp is ≤ 0.05 absolute score
Tier Badges & Transparency UI
"As a new user, I want to understand what my current tier means and how to improve it so that I can unlock better access and lower deposits."
Description

Surface Trust Tiers consistently across the app with accessible, color‑coded badges on profiles, item cards, booking screens, and messages. Include tooltips and a dedicated "Why this tier?" panel showing benefits, requirements, and top factors affecting the user’s tier. Provide a progress tracker with actionable next steps (e.g., "Complete ID check," "Get two vouches," "Complete 3 on‑time returns") and localized copy. Ensure WCAG‑compliant colors, dark mode support, and lightweight loading states. Track interactions (views, clicks) for analytics to measure comprehension and conversion to higher tiers.

Acceptance Criteria
Consistent Tier Badge Display
Given an authenticated user viewing any of: Profile, Item Card, Booking Screen, or Message Thread When the surface renders and Trust Tier data is available Then a color‑coded Trust Tier badge labeled "Tier {X}" is visible and clickable with an accessible name that includes the tier and a short benefit summary And the badge component uses the same variant (color, shape, size, typography) across all surfaces And on Item Cards and Booking Screens, if the item has a minimum tier, "Min Tier {Y}" is displayed and the UI indicates whether the user meets the requirement And if the user does not meet the requirement, a non‑blocking helper text appears with a link to "Why this tier?"
Tooltip and Why This Tier Panel
Given a user can interact with the Trust Tier badge or info icon When the user taps/clicks the badge or presses Enter/Space with focus Then a tooltip appears within 200 ms anchored to the badge with a one‑sentence explanation and a "Why this tier?" action And selecting "Why this tier?" opens a modal/panel within 300 ms that shows: current tier, benefits, requirements for next tier, and top 3 factors affecting the current tier And the panel is dismissible (Esc/Close), traps focus, restores focus to the trigger on close, and is operable with keyboard and screen readers And all links and CTAs are actionable and route to the appropriate flows without full page reload
Progress Tracker With Actionable Next Steps
Given a logged‑in user with any Trust Tier opens the Why This Tier panel or Profile > Trust When the view loads Then a progress tracker displays percent progress toward the next tier and an ordered list of next steps with statuses: Not Started, In Progress, Completed And next steps include: Complete ID check, Get two vouches, Complete 3 on‑time returns; each step has a primary CTA And completing a step updates the tracker state within 2 seconds of the backend confirmation without full page reload And if a step fails, an inline error is shown with retry guidance; partial completions persist across sessions
Localization and Copy Fallback
Given the app supports locales (at minimum en, es, fr) When the user’s locale is set or switched in settings Then all tier badge labels, tooltip text, panel copy, and progress step strings are displayed in the selected locale with correct pluralization and number/date formatting And if a translation string is missing, the UI falls back to English, logs a non‑fatal warning with key and locale, and does not display raw keys or placeholders And RTL layouts render correctly for RTL locales with mirrored icons and proper text direction
Accessibility and Dark Mode Compliance
Given WCAG 2.1 AA compliance is required When the Trust Tier badge, tooltip, and panel render in both light and dark mode Then text/icon contrast ratios meet or exceed 4.5:1 for normal text and 3:1 for large text/icons And interactive elements have visible focus states, 44x44 dp minimum touch targets, and are reachable via Tab/Shift+Tab with logical order And all components expose accessible names, roles, and states; screen readers announce tier level, min tier requirements, and next step statuses And reduced motion settings are respected (animations disabled or minimized) and no flashing content is introduced
Lightweight Loading and Fallback States
Given network latency or cold start causes tier data to load after view render When the view loads and tier data is not yet available Then a lightweight skeleton or placeholder badge appears within 150 ms and is replaced within 50 ms after data arrival And total additional payload for tier UI (per surface) is <= 5 KB gzipped and does not increase Time to Interactive by more than 50 ms on a 4G network And errors retrieving tier data show a neutral state "Tier info unavailable" with a Retry action and do not block primary flows And badge loading or errors do not cause cumulative layout shift > 0.1
Analytics: Interaction and Conversion Tracking
Given product analytics is enabled with user consent When a user sees a tier badge, opens the tooltip, opens the Why This Tier panel, or clicks a next step CTA Then the following events are emitted with properties: - TierBadge_Impression {surface, userTier, itemMinTier?, locale, theme} - TierBadge_Tooltip_Open {surface, userTier, locale} - WhyThisTier_Open {surface, userTier} - NextStep_Click {stepId, stepName, userTier, success:boolean} And events are sampled at 100% for launch and achieve >= 95% delivery within 5 minutes with exponential backoff retries for up to 24 hours And payloads exclude PII; userId is a pseudonymous ID; events fire only after consent=true And a funnel is calculable: Badge Impression -> WhyThisTier_Open -> NextStep_Click -> Tier_Upgraded, with daily counts available
Lender Minimum‑Tier Gate
"As a lender, I want to require a minimum trust tier for my premium gear so that I reduce risk without micromanaging each booking."
Description

Allow lenders to set a minimum required Trust Tier at the account level and per item listing, with sensible defaults and overrides. Enforce the gate during search (filtering visibility) and at booking time (blocking or routing to request flow). Provide clear borrower messaging when they do not meet the requirement, including reasons and guidance to level up. Expose lender‑side controls in listing creation/edit, bulk‑edit options for organizers, and audit logs of setting changes. Ensure compatibility with HOA/tenant group rules and API endpoints for partner integrations.

Acceptance Criteria
Set Account-Level Minimum Tier Default
Given a lender with an active account and access to Settings When the lender sets a Minimum Required Trust Tier at the account level and saves Then the value is persisted and returned by subsequent GET settings calls And the value cannot be set below the lender’s HOA/group-required minimum (if applicable) And an inline error is shown if the input violates the HOA/group minimum And any new listing created after save pre-fills its Minimum Tier with this account default
Per-Item Minimum Tier Override
Given a lender is creating or editing a listing When the lender sets a Minimum Required Trust Tier for that listing Then the listing stores this override and uses it instead of the account default And the UI pre-fills with the account default prior to change And the override cannot be set below the HOA/group-required minimum; violations show an error and are not saved And when the lender clears the override, the listing reverts to the account default
Search Visibility Enforced by Borrower Tier
Given a signed-in borrower with Trust Tier T performs a search When search results are returned Then only listings whose effective Minimum Required Trust Tier is ≤ T are included And listings above T are excluded from results and counts And for logged-out users, results hide gated listings and prompt sign-in to determine eligibility And the enforcement occurs server-side and is reflected in all API search responses
Booking Gate and Request Flow Routing
Given a borrower views a listing with effective Minimum Required Trust Tier R When the borrower attempts to book Then if the borrower’s Trust Tier < R, the instant booking is blocked and the borrower is routed to the request/approval flow And a clear inline message explains the block and required tier And no deposit hold is placed during the blocked attempt And if the borrower’s Trust Tier ≥ R, the booking proceeds per normal rules (including instant approval where applicable) And the gate is re-evaluated server-side at booking submission to prevent client bypass
Borrower Messaging and Level-Up Guidance
Given a borrower does not meet the Minimum Required Trust Tier for a viewed listing When the listing detail screen renders or a booking attempt is made Then the UI displays the listing’s required tier, the borrower’s current tier, and the specific reasons they do not qualify (e.g., missing ID check, insufficient vouches, on-time handoffs count) And the UI provides actionable CTAs to complete steps to level up (e.g., Start ID check, Request vouch) And messaging is accessible (meets color contrast and screen reader labeling) and localized for supported languages
Organizer Bulk Edit of Minimum Tier
Given an organizer selects multiple listings in the bulk edit tool When the organizer applies a Minimum Required Trust Tier value and confirms Then the system updates all selected listings that meet validation rules And any listing that would violate an HOA/group minimum is not updated and is listed with an explicit error in the bulk results report And a success/failure summary shows counts of updated, skipped, and failed listings And effective values are visible on the confirmation screen and via subsequent GET listing calls
Audit Logs for Minimum Tier Changes and Partner API Support
Given a change to Minimum Required Trust Tier at account or listing scope via UI or Partner API When the change is submitted and validated Then an audit log entry is created capturing actor (user or API client), timestamp, scope (account or listing), old value, new value, and source (UI/API) And audit logs are immutable and retrievable with filters by date range, actor, scope, and listing ID And Partner API provides authenticated endpoints to GET/PUT account- and listing-level minimum tier, enforcing HOA/group floors and returning standardized validation errors And all API changes are rate-limited and require appropriate permissions; unauthorized attempts are rejected with 401/403 and are audit-logged
Tier‑Based Deposits & Instant Approvals
"As a high‑tier borrower, I want lower deposits and instant approvals so that I can book items quickly without excessive upfront costs."
Description

Implement rules that adjust deposit amounts and approval workflows by Trust Tier: higher tiers receive lower deposit holds and may get instant auto‑approval; lower tiers see higher deposits or manual review. Integrate with Stripe for deposit authorization, capture, and release, with guardrails (min/max, currency, idempotency) and clear UI disclosures before checkout. Allow policy configuration per market and per lender (within platform limits), and emit events to the scoring engine on approvals, holds, and releases. Ensure edge‑case handling for expired holds, partial returns, and overlapping bookings with smart pickup windows.

Acceptance Criteria
Tiered Deposit Calculation with Guardrails
Given two borrowers with different Trust Tiers (T_high > T_low) booking the same item in the same market, when deposits are computed, then the higher-tier borrower’s deposit is less than or equal to the lower-tier borrower’s deposit. Given an item with a lender-defined minimum deposit within platform limits, when computing the borrower’s deposit, then the final deposit equals max(tier-based deposit, lender minimum) and does not exceed the platform/market maximum. Given a market policy with platform min/max deposits per currency, when an admin or lender attempts to save a policy outside limits, then the configuration is rejected with validation errors and is not persisted. Given a borrower’s Trust Tier changes during checkout, when the tier updates, then the displayed deposit recalculates within 300ms and the payment intent (if created) is updated or re-created safely. Given overlapping bookings cause smart pickup windows to auto-adjust, when deposit computation runs, then each booking’s deposit is computed independently using the adjusted windows and no duplicate holds are created for the same booking.
Instant Approval by Trust Tier with Lender Minimums
Given a borrower’s Trust Tier meets or exceeds the market’s instant-approval tier threshold and the item’s lender minimum tier, when the borrower submits the booking and the deposit authorization succeeds, then the booking is auto-approved within 2 seconds. Given a borrower’s Trust Tier is below the lender’s minimum or below the market instant-approval threshold, when the borrower submits the booking, then the booking enters Manual Review and notifications are sent to lender and borrower. Given instant approval is permitted but the deposit authorization fails or requires action (e.g., 3DS), when the borrower submits, then the booking remains unapproved and the UI prompts the borrower to complete payment verification or retry. Given a lender sets a stricter minimum tier than the market requires, when evaluating approval mode, then the lender minimum takes precedence within platform limits. Given a decision timeout occurs during instant approval evaluation, when the timeout threshold is reached, then the booking falls back to Manual Review and is logged for audit.
Stripe Authorization Idempotency and Currency Handling
Given a booking request with deposit amount A in market currency C, when creating a Stripe authorization, then exactly one authorization is created with an idempotency key derived from bookingId+attempt and amount/currency match A/C in minor units. Given transient network errors during authorization, when retries occur, then exponential backoff is applied up to N=3 attempts without creating duplicate holds, and the final result is reflected in the booking state. Given a user double-submits the checkout, when the backend processes both requests, then only one authorization exists for the booking and subsequent calls return the existing authorization. Given the market requires 3DS for deposits above threshold, when the authorization requires 3DS, then the flow prompts for SCA and only proceeds to approval after successful authentication. Given a different currency is selected or the user changes market, when recomputing deposit and authorizing, then the authorization uses the correct market currency and any prior authorization is voided before creating a new one.
Deposit Capture, Partial Capture, and Automatic Release
Given an on-time, undamaged return, when the lender marks the booking complete, then the authorization hold is released within 10 minutes and the borrower is notified. Given damage or late fees assessed C <= authorized amount A, when closing the booking, then C is captured and A−C is released; events reflect both amounts. Given assessed charges exceed the authorization (C > A), when closing the booking, then A is captured and an additional payment flow is initiated for C−A per policy; the borrower is shown an itemized breakdown. Given an authorization is due to expire before the booking’s end or adjusted pickup window, when T_expiry < T_needed, then the system re-authorizes with a new idempotency key before expiry; on failure, both parties are notified and the booking is flagged for manual review. Given no action is taken by lender within the grace period after scheduled return, when grace period elapses, then the authorization is auto-released and the booking is closed per policy.
Event Emission to Scoring Engine on Key Actions
Given a deposit authorization, capture, release, re-authorization, or failure occurs, when the action completes, then an event is emitted within 5 seconds with fields: eventId, eventType, bookingId, itemId, lenderId, borrowerId, trustTier, amount, currency, timestamp, outcome, and correlationId. Given an approval decision (auto or manual), when the decision is recorded, then an Approval.Decided event is emitted with decision source (auto/manual), rationale (tier/policy), and timing metrics. Given network or downstream issues, when emitting events, then the system retries with backoff and guarantees at-least-once delivery; consumers can deduplicate via eventId. Given PII policies, when emitting events, then no raw payment method details are included; only tokenized identifiers and masked data are sent. Given overlapping bookings and smart pickup adjustments, when events are emitted, then each booking has distinct correlationIds and adjusted window timestamps reflected in payloads.
UI Disclosures of Deposit and Approval Mode Before Checkout
Given a borrower views the checkout, when the deposit is computed, then the UI displays deposit amount with currency, that the amount is a hold (not a charge), and the borrower’s current Trust Tier. Given approval mode is determined, when conditions qualify for Instant Approval, then the UI labels the booking as “Instant Approval” with a brief reason (Tier threshold met) and a link to learn more; otherwise it shows “Manual Review” with an ETA. Given the borrower changes dates, items, market, payment method, or their Trust Tier updates, when these inputs change, then both the deposit amount and approval mode update within 300ms without page reload. Given Stripe authorization requires additional authentication, when the borrower confirms, then the UI prompts for 3DS and clearly communicates success/failure and next steps. Given legal/policy requirements, when the borrower confirms, then they must acknowledge deposit terms via a checkbox; confirmation is blocked until acknowledgment is provided.
Market and Lender Policy Configuration with Precedence
Given a platform admin configures a market, when saving policies, then they can set per-tier deposit scaling, instant-approval thresholds, platform min/max deposits, currency, and SCA requirements with validation. Given a lender configures an item, when saving settings, then they can set a minimum Trust Tier and an optional stricter minimum deposit within market/platform limits; out-of-bounds values are rejected with clear errors. Given conflicting settings, when evaluating policy, then the order of precedence is Platform Limits > Market Policy > Lender Settings, and the resulting effective policy is deterministic and testable. Given any policy change, when it is saved, then an audit log entry is recorded with who, when, what changed, and diffs; changes apply only to new bookings created after the change timestamp. Given feature flags per market, when the Trust Tiers feature is toggled, then existing bookings remain unaffected and new bookings follow the current flag state.
Appeals, Vouches & Audit Trail
"As a responsible borrower, I want a fair way to contest issues and add vouches so that my trust tier accurately reflects my behavior."
Description

Provide a structured flow for users to submit appeals or add community vouches that can influence their Trust Tier, with evidence upload, rate‑limited submissions, and SLA tracking. Build an admin console to review appeals, adjust scores, and annotate decisions. Maintain an immutable, searchable audit log of all trust‑impacting events (bookings, disputes, verifications, adjustments) for compliance and dispute resolution. Reflect appeal outcomes in the scoring engine with versioned change history, and notify users of decisions with guidance on next steps.

Acceptance Criteria
Submit Appeal With Evidence and Rate Limit
Given a logged-in user with a valid account And no more than 1 open appeal and no appeal submitted in the last 14 days And the user completes the appeal form with a reason (>= 20 chars) And uploads up to 5 evidence files (pdf|jpg|png|mp4, each <= 25 MB) that pass virus scan When the user submits the appeal Then the system creates an appeal record with status "Submitted" and SLA dueAt = submission_time + 72h And displays a countdown timer to SLA on the appeal detail view And prevents additional appeal submissions until the open appeal is resolved or 14 days elapse And sends confirmation via in-app receipt and email within 1 minute containing the appeal ID And writes an "appeal_submitted" trust-impacting event to the audit log
Admin Reviews Appeal and Adjusts Trust Score With Annotation
Given an admin with role "Trust_Reviewer" opens the appeals queue When the admin views an appeal, its user history, and evidence And selects a decision: Approve, Reject, or Request Info And enters a decision note (>= 20 chars) And if Approve, applies an allowed score adjustment (±0–20 points) or tier override per policy Then the system updates the appeal status accordingly (Resolved, Rejected, Info Requested) And records reviewer ID, timestamp, decision, and note And pauses the SLA clock while status = "Info Requested" and resumes upon user reply And writes "appeal_decided" and, if applicable, "score_adjusted" events to the audit log And enforces RBAC so only authorized admins can take these actions
Immutable Audit Log Captures Trust-Impacting Events and Is Searchable
Given any trust-impacting event occurs (booking, dispute, verification, vouch, appeal, admin adjustment) When the event is recorded Then an append-only log entry is created with event_id (UUID), actor_id, subject_id, type, UTC timestamp (ms), payload_hash (SHA-256), and previous_hash And the hash chain validates without gaps and a daily snapshot hash is generated And admins with "Audit_Viewer" role can filter by user, type, and date range and receive results within 2s for up to 10k events And selected results can be exported to CSV within 30s for up to 100k rows And all audit log read/export actions are themselves logged as audit events
Community Vouch Submission With Anti-Abuse Controls
Given a lender with Tier >= 2 and at least 2 completed handoffs in the last 90 days When the lender submits a vouch for a borrower with a reason (>= 20 chars) Then the system enforces: 1 vouch per lender→borrower per 30 days, max 5 vouches received per borrower per 7 days, and no self-vouching And suspicious patterns (e.g., reciprocal vouch loops or burst activity) flag the vouch for review And accepted vouches write a "vouch_added" event to the audit log and award a score weight (e.g., +5) up to a capped +15 per 90 days And rejected vouches notify the submitter with the reason
Scoring Engine Applies Outcomes With Versioned Change History
Given an appeal approval, rejection, or accepted vouch that affects trust score/tier When the scoring engine recalculates Then it creates a new score version with version_id, rule_version, inputs, before_score, after_score, reason_codes, and effective_at (UTC) And previous versions remain read-only and discoverable in the user's score history And any tier change derived from the new score updates atomically across profile and item eligibility checks within 1 minute And admins can roll back by promoting a prior version, which creates a new version and audit entries
Decision Notification With Next-Step Guidance and Localization
Given an appeal decision is recorded When notifications are dispatched Then the user receives in-app and email notifications within 5 minutes, localized to their preferred language with English fallback And the content includes outcome, updated score/tier, brief rationale, and a next-step CTA (e.g., complete ID check or supply more info) And delivery status is tracked; bounced emails create a persistent in-app banner until dismissed And notification templates are versioned and rendered safely (no HTML/script injection)

Weighted Vouches

Not all vouches count the same. Endorsements from proven neighbors (Power Lenders, HOA admins, on‑time streaks) carry more weight and gently decay unless reconfirmed. This resists fake rings, elevates credible reputation, and rewards consistent reliability.

Requirements

Vouch Weight Tiers
"As an organizer, I want endorsements from proven neighbors to count more so that borrower reputations reflect real reliability."
Description

Introduce role-based and behavior-adjusted vouch weights. Endorsers are classified into tiers (e.g., Power Lender, HOA Admin, Verified Neighbor), each with a configurable base coefficient. An endorser’s weight is further modulated by their reliability signals (on-time pickup/return streaks, dispute rate, verified identity/HOA role) to elevate credible voices. The system applies caps and normalization to prevent single-source dominance and ensures weights are versioned so historical calculations remain reproducible. Defaults are provided with environment-based overrides per neighborhood. This creates a durable foundation for trustworthy, explainable endorsements that accurately reflect community credibility.

Acceptance Criteria
Base Coefficients Applied by Endorser Tier
Given a neighborhood with default tier coefficients {Power Lender: 1.5, HOA Admin: 2.0, Verified Neighbor: 1.0} And an endorser with tier "Power Lender" When the endorsement weight is computed Then the base coefficient applied equals 1.5 And when the "Power Lender" coefficient is updated to 1.6, subsequent computations use 1.6 And the applied base coefficient is persisted alongside the weight
Reliability Modifiers Adjust Final Weight
Given policy modifiers m_streak = 1 + min(streak/10, 0.2), m_dispute = 1 - min(dispute_rate, 0.4), m_verify = 1.1 if verified_identity = true else 1.0, m_role = 1.3 if HOA Admin else 1.0 And an endorser with base coefficient = 1.0, streak = 12, dispute_rate = 0.05, verified_identity = true, role != HOA Admin When the endorsement weight is computed Then m_streak = 1.2, m_dispute = 0.95, m_verify = 1.1, m_role = 1.0 And the final weight equals 1.25 rounded to 2 decimals And if dispute_rate increases to 0.40, the final weight recalculates to 0.79
Cap and Normalize Aggregate Vouch Contributions
Given three endorsements with pre-normalization final weights [5.0, 3.0, 2.0] And MAX_SINGLE_SOURCE_SHARE = 35% When the aggregate vouch score is computed Then shares are normalized to [0.35, 0.39, 0.26] with two-decimal precision And no single endorser exceeds 35% of the aggregate share
Policy Versioning Ensures Historical Reproducibility
Given policy version v1 effective until 2025-09-01T00:00:00Z and version v2 effective from 2025-09-01T00:00:00Z And an endorsement created on 2025-08-15T12:00:00Z computed under v1 with final weight = 1.30 When the same endorsement weight is re-fetched after v2 activation Then the value remains 1.30 and the response includes policy_version = "v1" And new endorsements created on or after 2025-09-01T00:00:00Z compute under policy_version = "v2" And each weight record stores the policy version and the coefficient/modifier snapshot used
Time Decay and Reconfirmation of Vouches
Given a decay policy with half-life = 180 days and minimum_decay_floor = 0.30 And an endorsement with current (pre-decay) weight = 1.50 created 180 days ago When the decayed weight is computed Then the weight equals max(1.50 * 0.5, 1.50 * 0.30) = 0.75 And upon reconfirmation today, the decay age resets to 0 and the weight returns to 1.50 And at 360 days without reconfirmation, the decayed weight equals max(1.50 * 0.25, 1.50 * 0.30) = 0.45
Neighborhood Overrides Apply and Audit
Given global defaults {Power Lender: 1.5} and a neighborhood override for "Downtown HOA" {Power Lender: 1.7} And an endorser with tier "Power Lender" endorses a borrower in "Downtown HOA" When the endorsement weight is computed Then the base coefficient applied equals 1.7 And the weight explanation shows override_source = "neighborhood:Downtown HOA" And an endorsement in a different neighborhood uses the global default 1.5
Weight Explanation API Provides Transparent Breakdown
Given an endorsement weight exists with base = 1.5, modifiers {streak:1.2, dispute:0.95, verify:1.1, role:1.0}, decay_factor = 0.90, cap_adjustment = -0.10, normalized_share = 0.35, final_score = 1.58, policy_version = "v2" When a client requests GET /v1/endorsements/{endorsement_id}/weight Then the response status is 200 And the JSON body includes endorsement_id, base, modifiers, decay_factor, cap_adjustment, normalized_share, final_score, policy_version, neighborhood_override, computed_at And the values match the persisted computation for that endorsement
Time Decay & Reconfirmation
"As a lender, I want old endorsements to fade unless renewed so that current behavior is reflected."
Description

Implement gentle, configurable time-decay for vouch weights (e.g., exponential half-life with floor) so endorsements diminish in influence unless reconfirmed. Provide a low-friction reconfirmation flow: automated reminders to endorsers, one-tap renewal, cooldowns, and rate limits to prevent spam. Expose freshness metadata in UI (e.g., “reconfirmed 2 weeks ago”) and programmatically via API. Schedule periodic recomputation jobs and cache invalidation on reconfirm events. Ensure decay parameters are policy-driven per community and fully auditable for consistency and fairness.

Acceptance Criteria
Exponential Decay With Floor Per Community Policy
Given a vouch with originWeight W and lastReconfirmedAt T0 And community C has policy halfLifeDays = H and floor = F with policyVersion = V When t days have elapsed and the decay recomputation runs Then currentWeight equals max(F, W * 0.5^(t/H)) within 0.5% relative tolerance And currentWeight is non-increasing in the absence of reconfirmation events And the vouch stores policyVersion V used for the computation
Reminder-Driven One-Tap Reconfirmation
Given a vouch where (now - lastReconfirmedAt) >= reminderThresholdDays R And the endorser has not unsubscribed from reminders When the reminder job executes Then exactly one reminder is sent to the endorser for that cycle containing a one-tap reconfirm link that expires after E hours When the endorser activates the link within E hours Then lastReconfirmedAt is set to now, currentWeight is reset to originWeight, and a reconfirm event is recorded And the link is single-use and idempotent; subsequent activations perform no additional changes and return 200 no-op or 409 conflict
Cooldown and Rate Limits on Reconfirmation and Reminders
Given a successful reconfirm for endorser U on vouch V at time T When U attempts to reconfirm V before T + cooldownDays C Then the request is rejected with HTTP 429 and no state changes occur And across all vouches, U may perform at most L reconfirm actions per rolling hour; excess attempts return HTTP 429 And reminder delivery is capped at M reminders per endorser per rolling day; additional eligible reminders are deferred to the next window And C, L, and M are configurable per community and take effect within 10 minutes of change
Freshness Metadata Exposed in UI and API
Given a user profile with vouches When the profile is viewed in the UI Then each vouch displays freshness text in the form "reconfirmed <relative time> ago" derived from lastReconfirmedAt using the viewer’s timezone And if a vouch has never been reconfirmed, it displays "vouched <relative time> ago" When clients call the vouch API Then each item includes lastReconfirmedAt (RFC3339), lastVouchedAt, policyVersion, decayParams {halfLifeDays, floor}, originWeight, currentWeight, and freshnessAgeSeconds And after a reconfirm event, both UI and API reflect updated freshness and weights within 5 seconds or on next refresh, whichever happens first
Periodic Decay Recomputation and Event-Triggered Updates
Given the scheduler is configured with recomputationIntervalHours = D When D hours elapse Then a recomputation job runs, recalculates currentWeight for all due vouches, and completes with <0.1% failure rate after retries And recomputation is idempotent; rerunning the job produces the same persisted state When a reconfirm event is recorded Then the affected vouch is recalculated immediately and excluded from duplicate recalculation in the same batch
Community-Scoped Policy Configuration and Versioning
Given an admin of community C updates decay-related parameters (halfLifeDays H, floor F, reminderThreshold R, cooldownDays Cn, reconfirmRateLimit L, reminderRateLimit M) When the change is saved Then a new policyVersion V+1 is created scoped to C and becomes active for C only And existing vouches in C adopt V+1 on the next recomputation without affecting other communities And the active policyVersion for C can be retrieved via API
Auditability of Policies and Reconfirmations
Given audit logging is enabled When a policy in community C is created or modified Then an immutable audit record is stored with actor, timestamp, communityId, oldValue, newValue, reason, and policyVersion When a reconfirmation is attempted Then an audit record is stored with actor (endorser), timestamp, vouchId, communityId, outcome (success, cooldown, or rate-limited), and requestId And audit records are queryable by time range and community and exportable as CSV and JSON
Reputation Score Integration
"As a borrower, I want my trustworthy behavior to unlock smoother bookings so that I can borrow faster and with fewer hurdles."
Description

Aggregate weighted vouches into a unified Trust Score that is consumed across booking, calendar, and payments flows. Use the score to drive guardrails and rewards: dynamic deposit holds via Stripe, auto-approval thresholds, pickup window flexibility, and reduced friction for high-trust users. Provide SDK/API access for real-time checks, UI badges with clear explanations, and safe fallbacks if the score is unavailable. Include feature flags for gradual rollout, bias/impact monitoring, and thresholds configurable by admins. The integration must not hard-block access solely by score; it should adjust risk controls and require human review for edge cases.

Acceptance Criteria
Trust Score Aggregation from Weighted Vouches
- Given a user has vouches with roles and timestamps, when the Trust Score is recalculated, then role weights and time-decay coefficients configured by admins are applied and the score is produced in the 0–100 range. - Given a vouch is reconfirmed, when the Trust Score is recalculated, then the decay for that vouch resets as of the reconfirmation time. - Given a user has zero valid vouches, when the Trust Score is requested, then the baseline score S0 is returned. - Given recalculation is triggered twice within 60 seconds with no input changes, when the Trust Score is requested, then the same numeric score and reason codes are returned (idempotent). - Given a vouch is revoked or the endorser is flagged for fraud, when the next recalculation runs, then the Trust Score reflects the removal within 5 minutes and an audit event is emitted. - Given a batch recompute of 10,000 users, when the job runs, then p95 compute time per user is <= 200 ms and the job completes without timeouts.
Booking Auto-Approval and Guardrails by Trust Score
- Given Trust Score >= A_high, when a user submits a booking, then the booking is auto-approved without manual review and the risk controls use the high-trust profile. - Given A_low <= Trust Score < A_high, when a user submits a booking, then the booking proceeds with medium risk controls (e.g., deposit hold and phone verification) and no hard block occurs. - Given Trust Score < A_low, when a user submits a booking, then the booking enters a human-review queue within 1 minute, the user sees "Pending review," and the system does not auto-reject; SLA to resolve <= 2 hours. - Given an admin updates A_low/A_high in config, when a new booking occurs, then the updated thresholds apply within 5 minutes and the change is audit-logged. - Given the score service is unavailable, when a user submits a booking, then the booking uses the neutral risk profile and proceeds without a score-based block, and a fallback event is logged.
Calendar Pickup Window Flexibility by Trust Score
- Given Trust Score >= W_high, when the system allocates a pickup window, then the window expands by the configured high-trust increment without creating overlaps that violate existing reservations. - Given W_low <= Trust Score < W_high, when the system allocates a pickup window, then the baseline window applies with no additional expansion. - Given overlapping requests exist, when the algorithm applies trust-based flexibility, then no confirmed booking loses its guaranteed window and total shift per booking remains within the configured max shift. - Given the UI renders a booking for a high-trust user, when the pickup window is displayed, then an indicator explains the extended flexibility. - Given scheduling runs under load, when trust-based windows are computed for 100 concurrent requests, then p95 allocation time is <= 150 ms.
Payments: Dynamic Stripe Deposit Holds
- Given a Trust Score maps to deposit tier T, when a booking is created, then a Stripe authorization is created for the amount defined by T before confirming the booking. - Given an item is returned on time, when the booking completes, then the authorization is released within 5 minutes and no capture occurs. - Given a no-show is recorded per policy, when the booking completes, then the authorization is partially or fully captured per the configured rules and the action is audit-logged. - Given Stripe returns an error when creating the authorization, then the system applies the baseline deposit tier and proceeds without blocking the booking, and emits an alert. - Given an admin updates the score-to-deposit mapping, when subsequent bookings are created, then the new mapping is used and does not retroactively change existing authorizations.
Real-Time Trust Score SDK/API
- Given a service holds a valid OAuth token and user_id, when it calls GET /v1/trust-score, then the response includes {score, tier, reason_codes[], last_updated, ttl_seconds} with HTTP 200. - Given steady-state traffic, when the API is called, then p95 latency <= 200 ms and success rate >= 99.9% over 24h. - Given a client exceeds 100 requests per minute per key, when calls continue, then HTTP 429 is returned with a Retry-After header. - Given a user_id is unknown, when the API is called, then HTTP 404 is returned; given the scoring service is degraded, then HTTP 503 with Retry-After and cause=unavailable is returned. - Given the SDK is initialized, when a score is cached and ttl_seconds not expired, then repeated calls return the cached value; when expired, the SDK refreshes before returning. - Given a new API version is available, when clients call v1, then responses include deprecation headers and v1 behavior remains backward compatible until end-of-life date.
UI Trust Badge and Explanations
- Given a user has a Trust Score, when booking cards, calendar entries, and checkout screens render, then a Trust Badge with tier label is displayed consistently in all three surfaces. - Given a user interacts with the badge, when the tooltip opens, then it explains that the score comes from weighted vouches that gently decay unless reconfirmed, and links to "Learn more." - Given accessibility checks, when the badge renders, then color contrast meets WCAG AA, the tooltip is keyboard-navigable, and an accessible name is provided. - Given the feature flag is off for a cohort, when the UI renders, then no badge is shown and no related analytics events fire. - Given the score is unavailable, when the UI renders, then a neutral "Trust check pending" state appears without adding extra friction to the flow.
Rollout, Configurability, Monitoring, and Non-Blocking Safeguards
- Given feature flags are configured, when rollout is toggled by cohort (e.g., HOA admins, ZIP code, percentage), then enablement applies within 5 minutes and can be safely rolled back instantly. - Given admin users access configuration, when thresholds (auto-approval, pickup flexibility, deposit tiers) are changed, then changes validate, take effect without deploy, and are audit-logged with actor and timestamp. - Given weekly monitoring jobs run, when metrics are computed, then dashboards show auto-approval rates and average deposits by cohort (new vs returning users, organizer roles) and emit alerts when disparities exceed configured bounds. - Given a booking from a low-score user or when the score is unavailable, when the flow proceeds, then no hard block occurs solely due to the score; instead, neutral or increased controls apply and edge cases are queued for human review. - Given a reviewer resolves an edge-case queue item, when a decision is recorded, then outcomes are persisted with reason, actor, and timestamps, and the decision feeds back into model monitoring.
Anti-Collusion Safeguards
"As an HOA admin, I want the system to detect and discount suspicious vouch patterns so that community trust cannot be gamed."
Description

Detect and discount coordinated or fraudulent vouch behavior. Enforce eligibility rules (minimum account age/activity before a vouch counts), reciprocal-vouch caps, per-pair and per-cluster rate limits, and cooldown windows. Apply anomaly detection on vouch graphs (dense mutual clusters, burst patterns, single-IP/device/geo similarities) and route flagged items to a review queue. Suspicious vouches contribute zero or reduced weight until cleared. Provide transparent, privacy-respecting messaging to users and maintain tunable thresholds with audit logs. This protects the ecosystem from fake rings while preserving legitimate community growth.

Acceptance Criteria
Eligibility Gate Before Vouch Counts
Given a voucher with account age < MinAccountAge days OR fewer than MinActivity actions in ActivityWindow When the voucher submits a vouch Then the vouch is stored with status = "ineligible" and applied_weight = 0 And the vouchee’s reputation score does not change And the voucher is shown a privacy‑respecting message stating the unmet requirement and remaining time/activity And an audit log entry is recorded with rule_id = "eligibility_gate", voucher_id, vouchee_id, timestamp
Reciprocal-Vouch Caps and Per‑Pair Rate Limits
Given users A and B have reached ReciprocalCap counted vouches within RollingWindow When A submits an additional vouch for B Then the vouch is accepted-for-record with status = "reciprocal_cap_exceeded" and applied_weight = 0 And the UI/API response includes next_eligible_date for the pair And an audit log entry is recorded with rule_id = "reciprocal_cap" Given any user pair has submitted >= PairRateLimit vouches within PairRateWindow When another vouch is submitted for that pair Then the vouch is stored with status = "pair_rate_limited" and applied_weight = 0 And an audit log entry is recorded with rule_id = "pair_rate_limit"
Cluster Anomaly Detection Routes to Review Queue
Given the vouch graph contains a cluster with mutual edge density >= ClusterDensityThreshold or triangle_count >= TriangleThreshold within TimeWindow When the anomaly detection job runs Then all new vouches in the cluster since the last run are flagged = "suspicious" with reason = "cluster_density" And each flagged vouch is routed to the review_queue And applied_weight = 0 until review outcome is recorded And moderators see a queue item with cluster_id, node_count, edge_density, time_window, and sample edges And an audit log entry is recorded per vouch with rule_id = "cluster_anomaly"
Burst and Shared-Source Signals Reduce or Zero Vouch Weight
Given >= BurstCountThreshold vouches originate within BurstWindow from the same IP, device_fingerprint, or high-similarity geo area When the next vouch is submitted from a matching source Then a risk_score is computed using source signals And if risk_score >= HighRiskThreshold then applied_weight = 0 and status = "source_high_risk" And if MediumRiskThreshold <= risk_score < HighRiskThreshold then applied_weight = BaseWeight * ReductionFactor and status = "source_medium_risk" And raw IP/device identifiers are not exposed to users; only hashed identifiers are stored for security analysis And a user-facing message indicates unusual activity was detected without revealing PII And an audit log entry records rule_id = "shared_source_burst", signal_types, hashed_identifier, and thresholds used
Cooldown Window After Suspicious or Excessive Vouch Activity
Given a voucher triggers a suspicious_event or hits a rate/reciprocal cap for a specific vouchee When the voucher attempts another vouch for the same vouchee within CooldownWindow Then the API responds with HTTP 429 and a retry_after (seconds) header/body value And no new vouch record is created And the UI displays remaining cooldown time and guidance And an audit log entry is recorded with rule_id = "cooldown_enforced", voucher_id, vouchee_id, cooldown_remaining
Tunable Thresholds with Auditable Configuration Changes
Given an authorized admin updates anti-collusion thresholds via the config UI/API When the change is saved Then the new config is versioned with who, when, what (old_value -> new_value), and a mandatory reason And the change propagates to all detection services within PropagationSLA minutes And evaluations after propagation use the new values; prior decisions remain auditable under their original version And the admin can roll back to any prior version, which is also logged And an immutable audit trail is queryable by time range, rule_id, and actor
Manual Review Outcomes Retroactively Apply or Reject Vouches
Given a vouch is in review_queue with status = "suspicious" When a reviewer marks the outcome = "cleared" Then applied_weight is set to the appropriate computed base_weight (or policy-adjusted weight) and vouchee reputation is recalculated within RecomputeSLA minutes And both parties receive a privacy‑respecting notification of the outcome And an audit log records reviewer_id, outcome, timestamp, and weight_applied When a reviewer marks the outcome = "confirmed_suspicious" Then applied_weight remains = 0, status = "rejected_suspicious", and any applicable cooldown/rate limits persist And both parties receive a notification indicating the vouch did not count without exposing detection details And the review item is closed with a permanent audit record
Vouch Lifecycle & Audit Log
"As a user, I want to see how my reputation score is calculated so that I trust the system and can improve it."
Description

Maintain an immutable event history for each vouch: creation, source tier, base weight, decay snapshots, reconfirmations, suspensions, overrides, and final dispositions. Expose an admin/moderation UI for searching, filtering, and exporting vouch histories and score derivations. Provide user-facing explainability that outlines score drivers (sources, freshness, adjustments) without exposing sensitive information unless consented. Align with data retention policies and support data subject requests. Ensure all computations are reproducible from logged events for compliance and trust.

Acceptance Criteria
Append-only Vouch Event Ledger
Given a new vouch is created When any lifecycle action occurs (create, decay_snapshot, reconfirmation, suspension, override, disposition) Then an append-only event is written with fields: vouchId, eventType, timestampUTC, actorId/system, sourceTier, weightBefore, weightAfter, metadata, algorithmVersion, sequence And update/delete operations on existing events are rejected and logged And a tamper-evident checksum chain over the event stream is stored and verified on read
Reproducible Score Derivation from Events
Given a vouchId with an event history When the system recomputes the vouch weight using the recorded algorithmVersion and ordered by sequence ascending Then the recomputed weight exactly equals the currently displayed weight And the derivation trace lists each event’s contribution, decay factor, and adjustments And rounding is applied to 4 decimal places consistently across UI, API, and exports
Admin Audit UI: Search, Filter, Sort
Given an admin accesses the Vouch Audit UI When they filter by any combination of vouchId/userId, date range, eventType, sourceTier, status, and weight range and apply sort Then the first page (<=250 rows) returns with correct results and sort order And p95 response time for filtered queries is <= 2s on a dataset of 100k vouches and 1M events And selecting a row opens the full event timeline and score derivation
Admin Export of Vouch Histories and Derivations
Given an admin selects 1+ vouches from filtered results When they export as CSV or JSON Then the export includes for each vouch: ordered events, current score, derivation breakdown, algorithmVersion, and checksum And sensitive fields (endorser identity, notes) are redacted unless consent flags are true And the export completes successfully, is downloadable, and an audit record of the export is created
User Explainability with Privacy Controls
Given a user views a profile or item with a trust score based on vouches When they open “Why this score” Then they see top contributing sources with weights, freshness/decay status, recent reconfirmations, and any active suspensions/overrides And identities of endorsers are hidden unless explicit consent exists or the viewer is an admin with proper scope And the numbers and factors shown match the recomputation trace for that vouch
Data Retention and Data Subject Requests
Given a retentionPeriod is configured When the retention job runs Then events beyond the retention window are anonymized or purged per policy while preserving non-identifying aggregates needed for compliance reports And recomputation within the retention window remains reproducible; outside the window the UI/API return “insufficient data” with no PII Given a verified data erasure request for a user When the request is executed Then PII related to that subject is anonymized in events, UI, and exports within 48 hours, while audit integrity is preserved And request status, time to completion, and scope are logged
Admin Controls & Weight Configuration
"As an ops manager, I want to tune weights and thresholds without code changes so that we can adapt to community behavior quickly."
Description

Deliver an RBAC-protected dashboard to manage weight tiers, decay parameters, eligibility rules, anti-collusion thresholds, and integration cutoffs (e.g., deposit adjustments, auto-approval). Include versioned configurations, preview modes, and canary rollouts by neighborhood. Provide guardrails (validation, impact diffs, rollback) and observability (metrics, alerts) so operations can adapt policies without code changes. Changes propagate via configuration service with audit trails for accountability.

Acceptance Criteria
RBAC Enforcement for Admin Weight Dashboard
- Given an authenticated user without the Admin role, When they request the Admin Weight Dashboard endpoint, Then the server returns HTTP 403 with error_code=RBAC_FORBIDDEN and no configuration data is returned. - Given an authenticated Admin with scope limited to Neighborhood A, When they attempt to edit settings for Neighborhood B, Then the API returns HTTP 403 with error_code=RBAC_SCOPE_VIOLATION and no changes are persisted. - Given an authenticated Admin, When they load the Admin Weight Dashboard, Then the page renders within 2 seconds at p95 and an audit entry is recorded with user_id, action=VIEW_DASHBOARD, timestamp, and ip_address.
Weight Tiers and Eligibility Rules Validation
- Given an Admin on the Weight Tiers screen, When they submit a new tier, Then validation enforces unique key, name length 3–40 chars, and numeric weight between 0.10 and 5.00 with max 2 decimal places. - Given eligibility rule expressions are provided, When validated, Then only allowed fields/functions are accepted, cyclic references are rejected, and a sample evaluation passes within 50 ms per record or the API returns HTTP 422 with field-level errors. - Given invalid input, When submission occurs, Then the API responds HTTP 422 with structured error codes and no draft version is created.
Decay Parameters Configuration with Preview Mode
- Given an Admin adjusts decay settings, When half_life_days is set within 7–365 and Preview is enabled, Then the system computes projected score deltas for a 1,000-user sample and renders median/p90/p99 within 5 seconds with no side effects on live data. - Given Preview mode is active, When the Admin toggles between current and proposed settings, Then deltas are displayed and exportable as CSV, and the Save action remains disabled until Confirm is clicked. - Given the Admin clicks Apply from Preview, When confirmed, Then a draft version is created with a linked impact summary and no ACTIVE version is changed until Publish.
Versioning, Publish, and Safe Rollback
- Given a draft configuration, When the Admin clicks Publish with a change summary, Then a new version with an incremented version_id is created, audit trail is recorded, and activation_time is set. - Given a version is published, When clients poll the configuration service, Then 99% of services report the new active version_id within 60 seconds via heartbeat metrics. - Given the Admin triggers Rollback to version_id N, When executed, Then the previous version becomes ACTIVE within 60 seconds, rollback_reason is logged, and all integration cutoffs (e.g., deposit thresholds, auto-approval) revert accordingly.
Canary Rollout by Neighborhood with Impact Diffs
- Given an Admin configures a canary, When Neighborhoods A and B are targeted with a 20% holdback for 2 hours, Then only users in A and B receive the new configuration and others remain on baseline. - Given the canary is running, When auto_approval_error_rate > 1% for 10 consecutive minutes or deposit_hold_disputes p95 increases > 20% vs baseline, Then the rollout auto-pauses, sends an alert to #ops-sharehood within 1 minute, and no additional neighborhoods are upgraded. - Given the canary completes without threshold breaches, When promoted to 100%, Then the same version_id is activated globally and the canary impact diff report is attached to the audit record.
Anti-Collusion Thresholds and Alerts
- Given anti-collusion rules are configured (e.g., max 3 mutual vouches per pair per 30 days; max 10 vouches from the same /24 per day), When inbound events exceed thresholds, Then offending vouches contribute zero additional weight, entities are flagged, and a COLLUSION_DETECTED alert with rule_id and evidence is emitted within 1 minute. - Given a collusion flag exists, When an Admin views the dashboard, Then the rule_id, triggering evidence, impacted users count, and an Export CSV action are visible. - Given thresholds are edited, When saving, Then a 7-day dry-run estimate of suppressed vouches and affected deposit adjustments is displayed before publish.
Config Propagation, Caching, and Health Signals
- Given a configuration is ACTIVE, When edge services fetch it, Then client caches honor TTL ≤ 300 seconds and fall back to last_known_good on errors without blocking borrower flows. - Given the configuration service is unavailable, When a client experiences 3 consecutive fetch failures within 5 minutes, Then an ALERTING_CONFIG_OUTAGE is emitted and error budget burn is posted to the operations dashboard. - Given normal operation, When observing telemetry, Then propagation latency p99 < 60 seconds, fetch error rate < 0.5%, and audit log ingestion success ≥ 99.9% over a rolling 24-hour window.
API & Data Model Additions
"As a developer, I want clear APIs and data models for vouches so that I can integrate weighted reputation across the app."
Description

Extend the data model with normalized entities: vouches (endorser_id, endorsee_id, source_tier, base_weight, modifiers, created_at, last_reconfirmed_at, status), vouch_events, and trust_score snapshots/cache. Provide APIs: POST /vouches, POST /vouches/{id}/reconfirm, GET /users/{id}/trust-score, and admin endpoints for configuration. Ensure idempotency, pagination, filtering, and webhooks for score changes affecting bookings/payments. Optimize with background jobs and caches for low-latency reads during checkout and scheduling flows.

Acceptance Criteria
Create Vouch API - Idempotent Creation and Validation
Given a valid authenticated request with Idempotency-Key and payload {endorser_id, endorsee_id, source_tier, base_weight, modifiers?} When POST /vouches is called with endorser_id != endorsee_id and both users exist Then respond 201 Created with body including id, status="active", created_at, last_reconfirmed_at=created_at, and persist a single vouch record and a vouch_event of type "created" Given the same Idempotency-Key and identical payload within 24h When POST /vouches is called again Then respond 200 OK with the same vouch id, do not create duplicates, and do not emit duplicate vouch_events Given missing or invalid fields (e.g., base_weight out of range, unknown source_tier) When POST /vouches is called Then respond 422 Unprocessable Entity with machine-readable error codes and no records created Given endorser_id equals endorsee_id or either user does not exist When POST /vouches is called Then respond 409 Conflict (self-vouch) or 404 Not Found (missing user) respectively and no records created
Reconfirm Vouch API - Authorized Reconfirmation and Decay Reset
Given an existing active vouch and an authenticated caller who is the original endorser or an admin When POST /vouches/{id}/reconfirm is called Then respond 200 OK, update last_reconfirmed_at to now, create a vouch_event type "reconfirmed", and enqueue trust score recompute for endorsee Given a non-authorized caller When POST /vouches/{id}/reconfirm is called Then respond 403 Forbidden and make no changes Given the same caller retries within 24h with the same Idempotency-Key When POST /vouches/{id}/reconfirm is called Then respond 200 OK with unchanged last_reconfirmed_at and no duplicate vouch_event Given the vouch is revoked or not found When POST /vouches/{id}/reconfirm is called Then respond 409 Conflict (revoked) or 404 Not Found respectively
Trust Score Retrieval - Low-Latency Cached Read
Given a valid user id with existing vouches and a warm cache When GET /users/{id}/trust-score is called Then respond 200 OK within p95 ≤ 100ms (p99 ≤ 200ms) with body {trust_score:number, as_of, version, breakdown} Given a cold cache When GET /users/{id}/trust-score is called Then compute from snapshots/events and respond within p95 ≤ 250ms, and warm the cache for subsequent reads Given an unknown user id When GET /users/{id}/trust-score is called Then respond 404 Not Found Given recent vouch activity that changes the score When GET /users/{id}/trust-score is called within 1s of job completion Then the response reflects the updated trust_score and as_of ≥ last change time
Score Change Webhooks - Reliable Delivery and Security
Given a computed trust score change for a user that crosses configured thresholds impacting bookings or payment holds When the score snapshot is updated Then emit a webhook event trust_score.threshold_crossed with event_id, user_id, old_score, new_score, thresholds, and signature Given any trust score update (even without threshold crossing) When the snapshot changes Then emit a webhook event trust_score.updated with event_id and diff fields Given a subscriber endpoint is slow or unavailable When delivering the webhook Then sign the request with HMAC SHA-256 (header Sharehood-Signature with timestamp), retry with exponential backoff for up to 24 hours, and ensure at-least-once delivery with idempotency via event_id Given 1000 webhook events in staging When delivered to a healthy subscriber Then achieve ≥ 99% successful deliveries with p95 delivery latency ≤ 2s
Admin Config - Source Tiers, Weights, and Decay Rules
Given an authenticated admin with proper scope When PUT /admin/trust-config is called with a valid schema defining source_tier weights, base_weight bounds, decay_half_life_days, reconfirm_extension_days, and modifier rules Then respond 200 OK, persist a new config_version, audit the change, and apply new rules to subsequent computations Given a non-admin caller When PUT /admin/trust-config is called Then respond 403 Forbidden and do not change configuration Given a config update that materially alters weights or decay When the change is saved Then enqueue a background bulk recompute for all affected users and expose the running job status via GET /admin/trust-config/jobs/{id} Given GET /admin/trust-config is called by an admin When requested Then return the active config_version and history with pagination
Background Jobs - Snapshot Recompute and Cache Warmup
Given a vouch created/reconfirmed/revoked or a config change event When the event is persisted Then enqueue an idempotent job to recompute the endorsee's trust score snapshot, update caches, and emit webhooks if thresholds are crossed Given single-user recompute workload When processing jobs in the queue Then complete p95 ≤ 2s per user with retry-once behavior for transient failures and dead-letter after 5 attempts with reason captured Given a config change impacting ≥ 10k users When bulk recompute is triggered Then process at a sustained rate ≥ 10k users/hour without causing p95 latency regressions on GET /users/{id}/trust-score above specified SLOs
Pagination & Filtering - Vouches and Events Listing
Given admin needs to review vouches and vouch_events When GET /admin/vouches and GET /admin/vouch-events are called with limit and cursor parameters Then return paginated results with default limit=50, max=200, and next_cursor when more data exists Given filter parameters (endorser_id, endorsee_id, source_tier, status, created_at range, event_type) When the list endpoints are called Then apply filters server-side and return only matching records Given high request volume (100 RPS) in staging When listing endpoints are exercised Then respond within p95 ≤ 200ms and results are consistently ordered by created_at desc unless sort is specified

Bookend Proof

Pickup and return are both verified with quick, privacy‑safe geotagged snapshots plus a one‑time PIN. Each handoff generates a tamper‑resistant receipt for both parties, deterring disputes and speeding deposit releases.

Requirements

One-Time PIN Handoff
"As a borrower, I want a simple one-time PIN to confirm pickup and return so that both parties have a clear, undeniable record of the handoff."
Description

Generate, display, and verify a unique, time-bound one-time PIN (OTP) for both pickup and return events. The OTP is bound to the booking, item, and participants, with configurable validity windows aligned to the calendar slot. The lender enters the borrower’s PIN (or vice versa) to confirm the handoff, with rate limiting, lockout on repeated failures, and audit logging. The flow supports resend/regenerate with invalidation of prior codes, localization, accessibility, and clear UI prompts. Integrates with the booking service to gate state transitions (Reserved -> Picked Up -> Returned) and with the receipt service to include the verified OTP in signed proofs. Benefits include reduced fraud, clear accountability, and faster resolution of disputes.

Acceptance Criteria
OTP Generation Aligned to Calendar Slot (Pickup & Return)
Given a booking in Reserved state with scheduled pickup and return time windows and configured validity offsets (pickup_start_offset, pickup_end_offset, return_start_offset, return_end_offset) When the system generates an OTP for the next upcoming event (pickup or return) Then the OTP is a unique 6-digit numeric code bound to bookingId, itemId, borrowerId, and lenderId And the OTP activation time equals window.start + configured_start_offset and expiration equals window.end + configured_end_offset And any previously active OTP for the same booking and event type is immediately invalidated And the OTP is stored only as a salted hash (no plaintext) with an associated OTP fingerprint for receipts And an audit event "OTP_GENERATED" is recorded with timestamp, eventType (pickup|return), and actor=system
Pickup Verification via One-Time PIN (Lender Confirms Borrower)
Given a booking in Reserved state with an active pickup OTP and attempts_used < configured_attempt_limit within configured_attempt_window When the lender enters the borrower’s pickup OTP exactly as issued Then the OTP matches the current active OTP for that booking and event type And the booking state transitions from Reserved to Picked Up And the transition is idempotent; repeated correct submissions within 5 minutes do not create duplicate events And the verified OTP becomes immediately invalid for reuse And a signed pickup receipt is created including the OTP fingerprint, verification timestamp, and verifier role And an audit event "OTP_VERIFIED_PICKUP" is recorded with actorId, bookingId, and masked source channel And the UI displays a success confirmation within p95 < 2 seconds
Return Verification via One-Time PIN (Borrower Confirms Lender)
Given a booking in Picked Up state with an active return OTP and attempts_used < configured_attempt_limit within configured_attempt_window When the borrower enters the lender’s return OTP exactly as issued (or vice versa, per configuration) Then the OTP matches the current active OTP for that booking and event type And the booking state transitions from Picked Up to Returned And the transition is idempotent; repeated correct submissions within 5 minutes do not create duplicate events And the verified OTP becomes immediately invalid for reuse And a signed return receipt is created including the OTP fingerprint, verification timestamp, and verifier role And an audit event "OTP_VERIFIED_RETURN" is recorded with actorId, bookingId, and masked source channel And the UI displays a success confirmation within p95 < 2 seconds
Rate Limiting and Lockout on Failed OTP Entries
Given configured_attempt_limit, configured_attempt_window, and configured_lockout_duration When failed OTP entries for a booking and event type reach configured_attempt_limit within configured_attempt_window Then the OTP entry endpoint enforces a lockout for configured_lockout_duration for that booking and event type And any further attempts during lockout return HTTP 423 Locked with a localized error And the lockout status auto-resets after configured_lockout_duration without manual intervention And an audit event "OTP_LOCKOUT" is recorded with attempt_count and window And rate limiting is enforced per user and per booking to a maximum of configured_rate_limit per minute with HTTP 429 on breach
Resend/Regenerate OTP with Invalidation of Prior Codes
Given a booking with an active OTP and configured resend limits (configured_resend_limit_per_window, configured_resend_window) When a participant requests resend/regenerate for the current event (pickup or return) Then a new OTP is generated and all prior OTPs for that booking/event are immediately invalidated And resend requests are limited to configured_resend_limit_per_window within configured_resend_window; excess requests return HTTP 429 with a localized error And delivery uses the participant’s preferred verified channels (e.g., SMS, email, push) as configured And no OTP value is logged in plaintext; only fingerprints/hashes are logged And an audit event "OTP_RESENT" or "OTP_REGENERATED" is recorded with channel(s), bookingId, and requesterId
Localization and Accessible UI for OTP Handoff
Given the booking locale and accessibility settings are available When OTP prompts, errors, and confirmations are displayed or sent (UI, SMS, email, push) Then all user-facing text is localized to the booking locale with correct pluralization and numeral formatting And the OTP input supports keyboard-only navigation, screen readers (labels, aria-live for errors), and high-contrast mode meeting WCAG 2.1 AA for contrast and focus visibility And mobile clients present a numeric keypad for OTP entry and allow paste from clipboard And error states include clear, actionable text and do not reveal whether an entered code was partially correct And all images/buttons have accessible names and a visible focus state
Audit Logging, Security Binding, and Receipt Signing
Given OTP lifecycle events occur (generate, resend, verify, fail, lockout) When any such event is processed Then an immutable audit record is written including bookingId, itemId, eventType (pickup|return), actorId, timestamp, outcome, masked channel, and clientId/IP (where available) And OTPs are stored only as per-OTP salted hashes with HMAC fingerprinting; plaintext is never persisted And verification requires that the OTP’s binding (bookingId, itemId, borrowerId, lenderId) exactly matches the current context; mismatches are rejected with HTTP 403 And the receipt service is called with a signed payload including OTP fingerprint, eventType, verifier role, and timestamp; the receipt signature verifies successfully And logs and receipts are retrievable by authorized roles and subject to data retention policies defined in configuration
Privacy-Safe Geotagged Snapshots
"As a lender, I want privacy-safe photos with location and time at pickup and return so that I can verify the handoff without exposing sensitive details about my home or neighbors."
Description

Enable users to capture quick photos at pickup and return that include verified location and time while protecting privacy. The client app captures images, attaches coarse geolocation within a configurable geofence of the pickup/return location, and computes a perceptual hash. Sensitive content (faces, license plates, house numbers) is auto-blurred on-device before upload. Only redacted images and hashes are stored; raw originals and extraneous EXIF are discarded. The location and timestamp are attested by the device and cross-checked server-side against the booking window. Configurable retention policies minimize data storage; users see exactly what is stored and can access their images via the receipt. Integrates with the booking, receipt, and dispute services to provide trustworthy, privacy-preserving proof.

Acceptance Criteria
Pickup Snapshot: On-Device Redaction and Coarse Geotag
Given an active booking within the pickup window and device location services enabled When the borrower taps "Verify Pickup" and captures a photo Then faces, license plates, and house numbers are auto‑blurred on‑device before any network call And the stored image contains no EXIF beyond format essentials (e.g., orientation) And a coarse location token within the configured geofence and a device‑attested timestamp are attached And a perceptual hash of the redacted image is computed on‑device And only the redacted image, perceptual hash, coarse location token, and timestamp are uploaded And the original unredacted image and full EXIF are discarded and unrecoverable by the client app And if the device is outside the configured geofence plus tolerance, the upload is blocked with a clear error
Return Snapshot: Validation Against Booking Window
Given an active booking within the return window at the designated return location When the borrower captures a photo via "Verify Return" Then the server validates the attested timestamp against the booking’s allowed window and records pass/fail with reason And the server validates the location token against the configured return geofence And on success, the return proof is linked to the booking and marked complete And on failure, no proof record is saved and the user is shown actionable guidance to resolve (e.g., wait until window opens)
Tamper‑Resistant Receipt Contents
Given pickup and/or return proof exist for a booking When a receipt is generated Then the receipt includes for each event: redacted image thumbnail, perceptual hash, attested timestamp, coarse location descriptor, and immutable proof ID And the receipt is signed server‑side and verifiable for integrity And both parties can access the receipt from the booking detail without exposing unredacted content
Retention Policy and Data Minimization
Given an organization‑configured retention policy (e.g., 30/60/90 days) When the retention period elapses Then the redacted images and perceptual hashes are purged from storage And receipts remain accessible with placeholders indicating media have expired And users can view, at any time, an in‑app disclosure listing exactly what data are stored for their booking And purge actions are logged for admin auditability
Privacy Safeguards: PII Redaction Assurance
Given the on‑device redaction pipeline When a photo is captured Then a post‑redaction safety check runs on‑device to detect residual faces, plates, or house numbers And if residual PII is detected above the configured confidence threshold, submission is blocked and the user is prompted to retake And stored images contain no GPS EXIF, device identifiers, or other extraneous EXIF fields
Perceptual Hash Generation and Consistency
Given two captures of the same scene after redaction When perceptual hashes are computed on‑device Then hashes are deterministic across devices within the configured tolerance to enable duplicate detection server‑side And the stored hash corresponds to the redacted image bytes (not the original) and is verifiable by recomputation server‑side And hash collision rate meets the acceptance threshold on the test corpus (e.g., ≤ 1 in 10,000)
Error Handling: Limited GPS and Clock Drift
Given weak GPS signal or minor device clock drift When a user attempts to capture a proof photo Then the app falls back to network‑based coarse location sufficient to evaluate the geofence And a configured clock‑drift tolerance (e.g., ±5 minutes) is applied to attested time validation And if location or time cannot meet minimum validation, the attempt fails with clear, localized error messaging and retry guidance
Tamper-Resistant Receipt Generation
"As an organizer, I want tamper-resistant receipts for each handoff so that I have a reliable record to reference if questions or disputes arise."
Description

Automatically create an immutable receipt for each pickup and return that includes event metadata (booking ID, item ID, parties, timestamps), OTP verification result, geofence checks, and perceptual image hashes. The receipt is cryptographically signed server-side and stored in an append-only, write-once bucket with versioning and retention policies. Each party receives a shareable link and downloadable PDF/PKPass containing the signature and verification status. The receipt integrates with the notifications system for instant delivery, the booking timeline for in-app viewing, and the audit log for moderation. Provides a single source of truth to deter disputes and accelerates downstream actions like deposit releases.

Acceptance Criteria
Pickup Receipt Auto-Generation and Signing
Given an active booking and a scheduled pickup within a defined geofence (100 m radius) When the borrower completes pickup by submitting a geotagged snapshot and a valid 6-digit OTP and the event is marked Completed Then a receipt is created within 5 seconds containing: receiptId, bookingId, itemId, lenderId, borrowerId, eventType=pickup, clientTimestamp, serverTimestamp, otpVerified=true, geofenceResult (inside/outside with distance m), snapshotHash (64-bit hex), deviceId And the receipt payload does not embed raw image data and includes only snapshotId and perceptual hash values And the receipt is cryptographically signed server-side and includes signature (base64), algorithm, and keyId And the receipt is written to append-only storage and returns receiptId 201 Created And duplicate pickup completion retries return 200 and the same receiptId without creating a new object
Return Receipt Metadata Completeness
Given an active booking with a defined return location and geofence (100 m radius) When the borrower completes return by submitting a geotagged snapshot and OTP verification (success or failure recorded) Then a receipt is created within 5 seconds containing: receiptId, bookingId, itemId, lenderId, borrowerId, eventType=return, clientTimestamp, serverTimestamp, otpVerified (true/false), geofenceResult (inside/outside with distance m), snapshotHash (64-bit hex), returnCondition (enum) And the receipt includes a verificationStatus field derived from otpVerified and geofenceResult (ok/attention) And the receipt is cryptographically signed server-side
WORM Storage, Versioning, and Retention Enforcement
Given object storage is configured with object lock (governance), versioning enabled, and a 365-day retention policy When a receipt object is created Then the object has objectLockMode set, retentionUntilDate >= now + 365 days, and a versionId And overwrite or delete attempts before retentionUntilDate are rejected by storage and logged And updates can only create a new immutable version; prior versions remain readable
Instant Delivery and Shareable Link
Given both parties have at least one notification channel registered (in-app, email, or push) When a receipt is created Then in-app notification is delivered within 5 seconds and email/push within 10 seconds to both parties And the notification includes a tokenized shareable link that renders the receipt without login And the link token does not contain PII and has a TTL of at least 365 days or until explicit revocation And opening the link allows downloading PDF and PKPass for the receipt
PDF/PKPass Artifact Generation and Contents
Given a receipt exists for a booking event When a party views the receipt Then they can download a PDF and add a Wallet pass (PKPass) representing the receipt And the artifact includes: bookingId, itemId, masked party names, eventType, timestamps, otpVerified, geofenceResult, snapshotHash, signature (base64), algorithm, keyId, and a scannable QR code with receiptId and signature And each artifact is under 2 MB and renders within 2 seconds on a mid-tier device
Booking Timeline and Audit Log Integration
Given a booking with pickup and/or return events When a receipt is created Then the booking timeline shows a receipt entry with verification status and signature badge within 5 seconds And moderators can view an audit log entry containing receiptId, bookingId, actorId, action=create_receipt, timestamp, storage versionId And audit log search by bookingId or receiptId returns the entry within 1 second on indexed environments
Signature Verification and Tamper Detection
Given a published platform public key and a generated receipt When the receipt signature is verified against the canonical payload Then valid, unmodified receipts return verification=pass; any altered field returns verification=fail with reason=signature_mismatch And the verification API /receipts/{receiptId}/verify responds within 300 ms (p95) with status (pass/fail), keyId And the in-app viewer displays Verified/Invalid accordingly; deposit release automation only proceeds when both pickup and return receipts verify as pass
Automated Deposit Release Rules
"As a borrower, I want my deposit released automatically once I return the item with proof so that I don’t have to wait for manual approval."
Description

Implement business rules that automatically release or retain Stripe deposit holds based on successful return proof. When return OTP and geotagged snapshot validations pass, the system triggers immediate deposit release; if validations fail or are missing after the grace period, it opens a dispute window and pauses release. Rules support organizer-configurable grace periods, late-return fees, and partial charge scenarios (e.g., damage claim flagged by the lender). Integrates with Stripe (Payment Intents/Setup Intents) and the receipt service to reference signed proof. Edge cases (early pickup, late return, no-show) are handled consistently with clear user messaging and notifications.

Acceptance Criteria
Immediate Release on Valid Return Proof
Given a booking has an active Stripe deposit hold and a scheduled return time And the borrower submits a valid one-time return PIN (unused, not expired) And the return geotagged snapshot validates within the configured return geofence radius When both validations succeed Then the system triggers deposit release with Stripe and receives a success confirmation within 60 seconds And the receipt is updated with proof IDs, validation timestamps, and Stripe transaction identifiers And deposit_release_status is set to "released" and visible to both parties And lender and borrower receive confirmation notifications within 1 minute And the operation is idempotent so that repeated events or retries do not duplicate releases or notifications
Grace-Period Expiry Triggers Dispute Hold
Given a booking has an active Stripe deposit hold and organizer-configured grace_period is set And no valid return PIN and/or geotagged snapshot is recorded by grace_period end When the grace_period elapses Then the system sets deposit_release_status to "paused_pending_dispute" And opens a dispute case linked to the receipt with reason "missing_or_failed_return_proof" And, if policy auto-applies late fees at grace expiry, the late fee is calculated and recorded on the receipt (without releasing the hold) And lender and borrower receive notifications explaining the dispute window and next steps And no deposit funds are released until dispute resolution state changes to "resolved"
Late Return Fee With Partial Charge and Remainder Release
Given the item is returned after scheduled end plus configured grace_period And the return PIN and geotagged snapshot validations pass And a late return fee policy is active When the system computes the late fee based on configured rules (rate/cap) Then the late fee amount is partially captured from the deposit via Stripe And the remaining hold amount is released within 60 seconds of capture confirmation And the receipt records the late fee line item, captured amount, released amount, timestamps, and Stripe references And both parties receive notifications detailing the fee and the released remainder
Damage Claim Provisional Partial Charge
Given a lender flags a damage claim within the configurable dispute window And provides a structured reason and evidence attachments And the return PIN and geotag validations either passed or are not required for the claim When the claim is submitted Then the system captures a provisional damage amount up to the organizer-configured maximum from the deposit And immediately releases any remaining deposit amount And updates the receipt with claim ID, evidence links, captured amount, released amount, and Stripe references And sets dispute_status to "open" and deposit_release_status to "partial_released_pending_dispute" And notifies both parties with timelines and appeal instructions
Early Pickup, On-Time Return Still Releases
Given the borrower picked up the item earlier than the scheduled start within the approved window And the return occurs on or before the scheduled end time And the return PIN and geotagged snapshot validations pass When the return is processed Then no late fees are applied And the deposit is released within 60 seconds And the receipt reflects adjusted actual pickup/return timestamps and the release event And both parties receive release confirmations
No-Show at Pickup Deposit Handling
Given a booking reaches the pickup cutoff without a completed pickup PIN and geotag validation And organizer policy defines a no-show fee (which may be zero) When the cutoff is reached Then the system cancels the booking with reason "no_show" And, if a no-show fee > 0, captures that fee from the deposit and releases any remaining hold; otherwise, fully releases the hold And the receipt records the no-show status, captured amount (if any), released amount, timestamps, and Stripe references And borrower and lender receive notifications detailing the outcome and any fees
Stripe Idempotency, Retry, and Status Sync
Given any action that captures or releases deposit funds is initiated When the Stripe API call fails transiently (e.g., network timeout, 5xx) Then the system retries with exponential backoff up to 3 attempts using a stable idempotency key per booking event And upon success, updates internal state and receipt exactly once; upon final failure, sets deposit_release_status to "pending_gateway" and surfaces actionable messaging to users And no duplicate captures or releases occur across retries or repeated events And a background reconciler syncs statuses with Stripe within 5 minutes and resolves any "pending_gateway" states or alerts ops
Evidence Bundle & Dispute Workflow
"As a lender, I want an easy way to dispute a return with all the proof bundled so that I can resolve damages or late fees fairly and quickly."
Description

Provide a structured dispute flow that compiles an evidence bundle from bookend proofs: redacted images, location checks, timestamps, OTP results, and the signed receipts. Either party can initiate a dispute within a configurable window; both can add notes and additional photos. The system timestamps all actions and maintains an audit trail. Organizers and support staff get a dashboard to review evidence, apply outcomes (refund, partial charge, fee), and communicate decisions. Integrates with notifications, Stripe for adjustments, and the booking timeline for status visibility. Reduces resolution time and ensures fair, transparent outcomes.

Acceptance Criteria
Dispute Initiation Window and Eligibility
Given a booking is closed with pickup and return proofs When either party opens the booking within the configured dispute window Then a Start Dispute action is visible and enabled to them Given the dispute window has expired When the user attempts to create a dispute via UI or API Then the Start Dispute action is not shown and the API returns 403 Given a dispute already exists for a booking When the other party attempts to create another Then the system prevents duplicates and returns the existing dispute reference Given a dispute is created When both parties view the booking timeline Then the dispute appears with status Open and a link to the dispute thread
Automatic Evidence Bundle Compilation
Given a dispute is created When the evidence bundle is generated Then it includes redacted pickup and return images, geolocation check result with masked coordinates, ISO 8601 UTC timestamps, OTP verification results, and signed pickup/return receipts Given any expected evidence asset is missing When the bundle is generated Then the bundle marks the asset as Missing with reason and flags the dispute as Needs Review Given the bundle is stored When a reviewer opens it Then an immutable audit trail lists each action with actor, timestamp, action type, and a SHA-256 hash of the bundle snapshot Given a bundle export is requested When the download link is issued Then assets are watermarked with the dispute ID and the link expires in 48 hours
Participant Notes and Additional Photos
Given a dispute is open When a party adds a note or photo Then the system timestamps it, attributes it to the party, virus-scans it, and stores it with a content hash Given file constraints When a user uploads attachments Then only JPG, PNG, HEIC, and PDF up to 20 MB each are accepted and a maximum of 10 attachments per party is enforced Given new evidence is added When the other party views the dispute Then they can see it within 10 seconds and receive an in-app notification Given an author attempts to remove their attachment When the deletion is confirmed Then the attachment is soft-deleted, retained in the audit trail, and hidden from the other party
Reviewer Dashboard and Decisioning
Given a reviewer with appropriate role accesses the Disputes Dashboard When they load the list Then they can filter by status, age, booking ID, parties, and outcome and sort by age and priority Given an open dispute is selected When the reviewer opens it Then they can view the full evidence bundle, add internal notes, and select an outcome: refund, partial charge, fee only, or no action Given a monetary outcome is selected When the reviewer confirms Then a reason code and free-text explanation are mandatory and recorded in the audit trail Given a decision is submitted When processing completes Then the dispute status changes to Resolved and both parties receive the decision message with outcome and rationale
Stripe Adjustments and Idempotent Processing
Given a refund, partial charge, or fee outcome is applied When executed Then the system creates the corresponding Stripe operations using idempotency keys and records the Stripe charge/refund IDs in the audit log Given a Stripe error occurs When processing the adjustment Then the system retries up to 3 times with exponential backoff and on failure rolls back local state and marks the dispute as Action Required Given a deposit hold exists for the booking When a dispute is open Then the hold is extended until resolution or the maximum hold duration is reached, whichever comes first Given an admin reverses a prior decision When reprocessing adjustments Then prior Stripe operations are reconciled and the audit trail links all related transactions
Booking Timeline Visibility and Notifications
Given a dispute is created When viewing the booking timeline Then a Dispute Opened event appears with timestamp and opener identity and automatic deposit release is paused Given any dispute update occurs (new evidence, status change, decision) When it is recorded Then both parties receive localized in-app and email notifications with deep links to the dispute Given a notification delivery failure is detected When a bounce or webhook error is received Then the system attempts an alternate channel if available and logs the failure in the audit trail Given a dispute is resolved When users view the booking timeline Then the outcome, adjusted amounts, and resolution timestamp are displayed and the deposit state reflects the decision
Privacy, Redaction, and Access Control
Given evidence images are displayed to non-reviewers When viewed Then faces and license plates are redacted and EXIF metadata is stripped Given a user without access requests a dispute or its evidence When the API is called Then a 403 is returned and the attempt is logged with user ID and timestamp Given a reviewer views geolocation evidence When displayed Then coordinates are rounded to 3 decimal places unless escalated access is granted with justification captured Given an evidence export link is generated When accessed Then a signed URL is required and the link expires after 48 hours
Offline Capture & Deferred Sync
"As a borrower in a low-signal area, I want to complete pickup and return proof offline so that the handoff isn’t blocked and syncs automatically when I’m back online."
Description

Support low-connectivity scenarios by allowing OTP entry and snapshot capture offline with secure local storage and deferred synchronization. The app records the event with a monotonic timestamp, stores redacted images and perceptual hashes encrypted at rest, and queues a signed update to the server. A short-lived verification code is displayed to both parties for mutual confirmation, and the server reconciles upon reconnect, validating sequence, times, and geofence within tolerances. Clear UI indicates pending status and sync results. Ensures handoffs can be verified without reliable cellular data, maintaining trust and continuity of operations.

Acceptance Criteria
Offline Pickup Handoff: OTP and Snapshot
Given the device has no internet and the user is on the pickup step for a booked item When the borrower provides the one-time PIN and both parties capture the required snapshots Then the app accepts the PIN offline, records a monotonic timestamp, applies on-device redaction before write, encrypts artifacts at rest, and saves a pending handoff record with a unique event ID. Given the offline pickup handoff is recorded When the record is saved Then a short-lived verification code (8 digits) is displayed to both parties for up to 120 seconds and is bound to the event ID. Given the pickup handoff was saved offline When the user attempts to modify or delete the snapshots or PIN Then the app prevents edits and only allows full deletion via an explicit Cancel Handoff action with confirmation.
Deferred Sync: Signed Queue and Retry
Given one or more pending handoff records exist and connectivity is unavailable When the app is backgrounded, closed, or the device reboots Then the pending queue persists and remains intact upon relaunch. Given connectivity becomes available When sync starts Then each queued event is serialized with event ID, monotonic and wall-clock timestamps, geolocation, redacted image perceptual hashes, and a device-bound signature, and sent to the server. Given a transient failure (HTTP 5xx or network error) occurs during sync When retry logic runs Then the client retries with exponential backoff up to 8 attempts over 24 hours and shows remaining attempts in the UI. Given the server returns success for an event When the client receives the acknowledgment Then the event is marked Synced exactly once; duplicate acks or submissions are handled idempotently.
Server Reconciliation: Sequence, Time, Geofence Validation
Given the server receives offline pickup or return events for a booking When reconciling sequence Then a return event is accepted only if a pickup exists and the return’s monotonic timestamp is greater than the pickup’s. Given event timestamps may differ from server time When validating time tolerances Then events occurring within booking windows are accepted with a clock-skew tolerance of ±3 minutes; otherwise the event is flagged Needs Review. Given geolocation is provided When validating geofence Then the capture location must be within 100 meters of the designated pickup/return location; otherwise the event is rejected with reason Geofence Out of Bounds. Given all validations pass When pickup and/or return are reconciled Then the server issues a tamper-resistant receipt to both parties and releases the deposit hold within 60 minutes.
User Feedback: Pending, Progress, and Sync Outcomes
Given a handoff is recorded offline When the record is saved Then the UI shows a persistent Pending Sync badge within 1 second on the booking detail and a queue count on the home screen. Given syncing is in progress When bytes are being uploaded Then a progress indicator is displayed and remains responsive; cancel pauses the upload and leaves the record pending. Given the server accepts the event When the acknowledgment is received Then the status updates to Verified with server-confirmed time and location, and the user receives an in-app notification and optional push. Given the server rejects the event When the result is received Then the UI shows Failed with a human-readable reason and a CTA to Retry or Contact Support; selecting Retry requeues the event.
Image Redaction, Encryption, and Hash Integrity
Given snapshots are captured offline When they are processed Then face/license-plate redaction is applied client-side before disk write; files are encrypted at rest using the platform keystore; and perceptual hashes are computed from the redacted pixels. Given the event later syncs When the server validates integrity Then the server recomputes perceptual hashes from the uploaded redacted images and accepts only if Hamming distance is ≤ 6 versus client hashes; otherwise it rejects with reason Hash Mismatch. Given local storage is inspected When a security test is conducted Then snapshot files and PIN values are not readable by other apps/users; PINs are stored only as salted hashes with no reversible plaintext.
Extended Offline, TTL, and Conflict Resolution
Given the device remains offline after a handoff When time since capture elapses Then the client retains the pending record for at least 72 hours; after TTL expiry the record is marked Expired and cannot auto-sync. Given the app reconnects after TTL expiry When the user attempts to sync Then the server accepts only if the booking is still open; otherwise it returns Conflict and provides next steps to submit manual proof. Given the same event is submitted multiple times (e.g., after reinstall) When deduplication runs Then events with the same event ID and valid signature are treated idempotently and do not create duplicate receipts.

Deposit Flex

Deposit holds scale to your trust tier and recent reliability. Trusted borrowers see smaller holds and faster reversals; new users get clear milestones to reduce holds. Lenders stay protected without scaring off cautious first‑timers.

Requirements

Trust Tier Engine
"As a frequent borrower, I want my reliable history to increase my trust tier so that my deposit holds are smaller and released sooner."
Description

Implements a real-time, event-driven trust scoring system that classifies borrowers into tiers (e.g., Bronze, Silver, Gold, Platinum) based on verified identity status, account age, on-time return rate, incident/dispute history, payment method health, organizer/HOA endorsements, and recent booking reliability (last 90 days). The tier determines deposit multipliers and hold reversal SLAs. The engine recalculates on key events (booking, pickup, return, dispute) and via nightly jobs, persists tier snapshots, exposes a read-optimized API to checkout, and surfaces the current tier and next-tier criteria to the UI. Provides sane defaults and graceful degradation if signals are missing.

Acceptance Criteria
Real-time Tier Recalculation on Key Events
Given a borrower with an existing tier snapshot and a new trust-impacting event (booking_created, pickup_confirmed, return_checked_in, dispute_opened, dispute_closed) is ingested When the event is processed Then the engine recomputes the trust score and tier and persists a new snapshot within 2 seconds of event ingestion Given duplicate delivery of the same event_id When the engine processes it Then only one snapshot is created (idempotency) and the resulting tier is unchanged Given a tier change occurs When the snapshot is persisted Then a "tier.updated" domain event is published within 2 seconds with borrower_id, old_tier, new_tier, snapshot_id Given the last_90_days reliability inputs exist When the score is recomputed Then events older than 90 days are excluded from reliability metrics
Nightly Tier Rebuild and Backfill
Given the nightly job window starts at 03:00 UTC When the job runs Then 100% of active borrowers are recalculated and a snapshot is written if the computed tier differs from the latest snapshot Given transient computation failures When they occur Then the job retries each failed borrower up to 3 times with exponential backoff and writes failures to a dead-letter queue Given a dataset of 1,000,000 active borrowers When the job runs Then processing completes within 2 hours and emits a completion metric with totals, failures, duration Given the job completes When auditors query for a date Then a rebuild_run record exists with start_time, end_time, processed_count, failed_count
Deposit Multiplier and Hold Reversal SLA at Checkout
Given a checkout request with item_base_deposit and borrower_id When checkout calls the trust engine Then the returned payload includes current_tier, deposit_multiplier, hold_reversal_sla that match the active configuration for that tier Given the multiplier is applied When the deposit hold is computed Then deposit_amount = round_up_to_cent(item_base_deposit * deposit_multiplier) Given the hold is released When the booking completes without incidents Then the reversal is initiated no later than the configured SLA for the tier Given the trust engine is unavailable or returns 404 for the borrower When checkout proceeds Then the system uses the default tier configuration and logs a degradation event with correlation_id
Tier Snapshot Persistence and Auditability
Given a tier recomputation occurs When the snapshot is stored Then the record contains borrower_id, tier, numeric_score, inputs_version, event_id (nullable for nightly), created_at, reason_code, and is immutable (append-only) Given a borrower_id When querying snapshots Then the API returns the last 100 snapshots sorted by created_at desc within 300 ms p95 Given two recomputations with the same event_id When snapshots are written Then only one record exists with that event_id for that borrower Given retention policy of 24 months When snapshots exceed retention Then older records are archived to cold storage and remain queryable via the audit endpoint within 2 seconds p95
Read-Optimized Trust API for Checkout and UI
Given GET /trust/v1/tiers/{borrower_id} When called with a valid borrower Then respond 200 with current_tier, numeric_score, deposit_multiplier, hold_reversal_sla, next_tier_summary, last_updated Given cache headers are enabled When the same borrower is requested Then ETag is returned and conditional requests with If-None-Match yield 304 when unchanged Given normal operation When measuring latency Then p95 latency is ≤ 150 ms and error rate ≤ 0.1% over a 24h window Given an unknown borrower When requested Then respond 404 and include default_tier_hint in the payload Given a versioned API When clients send an unsupported version Then respond 426 or 400 with a link to the supported version
Graceful Degradation with Missing Signals
Given one or more signals are missing or delayed (identity_status, payment_method_health, endorsements) When the engine computes the score Then default weights are applied and the borrower is assigned the configured baseline tier without raising errors to the client Given missing signals later arrive When they are ingested Then the engine triggers an immediate recomputation and publishes a "tier.updated" event if the tier changes Given degraded mode is active When logging/metrics are inspected Then a degradation metric and structured logs with missing_signal_codes are emitted for each affected computation
UI Surfacing of Tier and Next-Tier Criteria
Given a borrower opens the Account > Trust tab or the checkout review screen When the UI requests trust data Then it displays current tier name and badge, deposit hold multiplier, and hold reversal SLA exactly as returned by the trust API Given the engine provides next_tier_summary When the UI renders it Then it shows up to 3 actionable steps (e.g., verify ID, maintain 90% on-time returns over next 5 bookings, add verified payment method) sourced from the payload without client-side inference Given the borrower’s tier changes When the change event is published Then the UI reflects the new tier within 5 minutes or on next page load, whichever is sooner
Dynamic Deposit Calculator
"As a cautious first-time borrower, I want to see exactly how my deposit is calculated so that I understand the hold and feel comfortable proceeding."
Description

Calculates per-booking deposit hold amounts in real time using item value, category risk, lender-configured floors/caps, borrower trust tier, booking duration, outstanding holds, and recent reliability signals. Applies platform-wide minimum/maximum limits and category multipliers, with lender overrides constrained to policy bounds. Produces an explainable breakdown displayed at checkout before authorization, then places a preauthorization via Stripe with idempotency, retries, and fallback to safe defaults if any signal is unavailable. Supports currency conversion, tax/fee exclusions, and caching for consistent quotes within a session.

Acceptance Criteria
Base Deposit Calculation Determinism
Given fixed inputs (item_value=750.00 USD, category_multiplier=1.3, duration_hours=48, borrower_tier="Standard", outstanding_holds=0, lender_floor=50, lender_cap=600, platform_min=25, platform_max=800) When the calculator runs Then it returns a single numeric deposit within [25, 800] and not less than 50 or greater than 600. Given the same inputs across three invocations within one request When the calculator runs Then the output is identical and rounded to 2 decimal places. Given identical inputs with different non-functional metadata (e.g., user-agent) When the calculator runs Then the output is identical. Given any computed deposit When the calculator completes Then the result is >= 0 and expressed in the booking display currency.
Platform Limits and Lender Overrides Enforcement
Given raw_computed_deposit=$10 and platform_min=$25 When limits are applied Then final_deposit=$25. Given raw_computed_deposit=$1200 and platform_max=$800 When limits are applied Then final_deposit=$800. Given lender_floor=$100, platform_min=$25, raw=$80 When limits are applied Then final_deposit=$100. Given lender_cap=$300, platform_max=$800, raw=$450 When limits are applied Then final_deposit=$300. Given an override attempt where floor < platform_min or cap > platform_max When saving overrides Then the save is rejected with validation error and no change is applied. Given overrides where floor > cap When saving overrides Then the save is rejected and previous valid values are retained.
Borrower Risk Signals Scaling
Given identical booking details with borrower_tier="New" and borrower_tier="Trusted" When the calculator runs Then deposit(New) > deposit(Trusted) by the configured tier multipliers and both values are within platform bounds. Given borrower has 2 late returns within last 60 days When reliability penalties are applied Then the deposit increases by the configured reliability factor for that tier and does not exceed platform_max. Given outstanding_holds_total=$200 and outstanding_holds_threshold=$150 and block_if_outstanding_exceeds=true When the calculator runs Then the booking is blocked with error OUTSTANDING_HOLDS_LIMIT and no authorization is attempted. Given outstanding_holds_total=$200 and block_if_outstanding_exceeds=false When the calculator runs Then an outstanding_holds_adjustment is added per policy and final_deposit remains within platform bounds. Given trust-tier or reliability service timeout When signals are unavailable Then default multipliers (tier="Standard", reliability="Neutral") are used, fallback_reason is logged, and limits are still enforced. Given fallback defaults applied within a session When the user recalculates without material changes Then the same defaults persist and the quote remains consistent.
Duration and Category Risk Effects
Given identical inputs except duration=24h vs duration=72h When the calculator runs Then deposit(72h) >= deposit(24h) according to the configured duration factor. Given category "Power Tools" multiplier=1.4 and category "Books" multiplier=0.8 with same item_value and duration When the calculator runs Then deposit(Power Tools) > deposit(Books). Given duration crosses a threshold (e.g., 48h to 49h) When duration thresholds are applied Then the step change matches the configured threshold table. Given duration <= 0 When the calculator normalizes duration Then minimum billable duration is used and the calculation succeeds without error.
Currency Conversion and Tax/Fee Exclusions
Given item currency=EUR and display currency=USD and FX rate locked at time T (1 EUR=1.10 USD) When the calculator runs Then deposit is computed in item currency excluding taxes/fees, converted to USD using the locked rate at T, and rounded per currency rules. Given taxes=10% and service_fee=5% on item_value When the calculator runs Then taxes and service_fee are excluded from the deposit base. Given FX provider outage and last_known_rate within TTL When conversion is needed Then last_known_rate is used and quoted as such; if no rate within TTL, checkout is blocked with FX_UNAVAILABLE and no authorization is attempted. Given lender floors/caps defined in lender currency When the calculator runs Then floors/caps are enforced using consistent one-time conversion to the calculation currency without double conversion.
Explainable Breakdown at Checkout and Session Caching
Given a checkout quote When the breakdown is displayed Then it lists item_value_base, category_multiplier, duration_factor, trust_tier_adjustment, reliability_adjustment, outstanding_holds_adjustment, limits_applied, currency_conversion, and final_deposit with amounts and units. Given the final_deposit shown to the user When the authorization is created Then the authorized amount equals final_deposit. Given user refreshes within 15 minutes with no material changes When the quote regenerates Then final_deposit and breakdown are identical and the same quote_id is reused. Given a material change (e.g., duration or item) within the session When the quote regenerates Then quote_id changes and the breakdown reflects updated inputs.
Stripe Preauthorization Idempotency and Error Handling
Given a booking attempt When creating the Stripe authorization Then an idempotency_key derived from booking_id and quote_id is used for all attempts. Given transient Stripe errors (e.g., 5xx, rate limits) When retries occur Then up to 3 retries with exponential backoff are attempted and only one authorization exists on Stripe. Given Stripe hard decline or failed 3DS When handling the response Then the booking is not confirmed, error AUTHORIZATION_FAILED is shown, and no capture is attempted. Given duplicate user submissions (double-click) When concurrent requests arrive Then only one authorization is created; the other receives the existing authorization details due to idempotency. Given a successful authorization When persisting results Then Stripe IDs, authorization expiry, and linkage to quote_id are stored for audit.
Accelerated Hold Reversal
"As a trusted borrower, I want my deposit hold released immediately after I return an item so that my funds aren’t tied up."
Description

Automates deposit hold release based on return confirmation events and tier-based SLAs. For higher trust tiers, initiates immediate release upon lender confirmation or auto-complete of the return window; for lower tiers, applies short verification buffers. Handles partial retention if a damage/no-show claim is opened within the claim window, otherwise releases in full. Integrates with Stripe to manage preauth reversal timing, retries failed reversals with exponential backoff, and provides real-time status and ETA to the borrower. Ensures idempotent operations, audit trails, and reconciliation against platform ledgers.

Acceptance Criteria
Immediate Release on Lender Confirmation (High Trust Tier)
Given a borrower in High trust tier with an active deposit preauthorization hold H on Stripe And a tier policy where releaseBuffer = 0 minutes for High tier And the lender marks the item as returned at time T0 When the platform receives the lender return confirmation event Then the system transitions hold H status to "Releasing" within 30 seconds of T0 And the system initiates a Stripe reversal for hold H within 120 seconds of T0 using a stable idempotency key derived from holdId and eventId And the borrower sees status "Releasing" with an ETA timestamp in the status API within 2 minutes of T0 And an audit log entry is recorded with holdId, borrowerId, lenderId, tier, triggeringEventId, previousState, newState, initiatedAt, processorRequestId
Auto-Release on Return Window Auto-Complete (High Trust Tier)
Given a borrower in High trust tier with an active hold H And the scheduled return window ends at T_end without a lender confirmation And no claim exists on H at or before T_end When the auto-complete job runs at or within 5 minutes of T_end Then the system initiates a Stripe reversal for H within 2 minutes of the job start And sets hold status to "Released" upon successful reversal and records processor response And the borrower status API reflects "Released" with releasedAt timestamp within 1 minute of processor success And the operation is idempotent if the job runs more than once
Verification Buffer Before Release (Low Trust Tier)
Given a borrower in Low trust tier with an active hold H And tier policy config sets releaseBuffer = 30 minutes for Low tier and claimWindow = 24 hours And the lender confirms item return at T0 When no claim is opened for H before T0 + 30 minutes Then the system initiates a Stripe reversal for H between T0 + 30 minutes and T0 + 32 minutes And the borrower status API shows ETA = T0 + 30 minutes immediately after T0 And if a claim is opened before T0 + 30 minutes, no reversal is initiated at buffer expiry and claim handling takes precedence
Partial Retention on Claim Within Claim Window
Given an active hold H with amountHeld = $A And a claim is opened at T_claim within the configured claimWindow with requested amount $C When the release process evaluates H Then the system captures or retains min($C, $A) from H and releases the remainder $A - min($C, $A) And the borrower status API shows "Partially Released" with fields retainedAmount and releasedAmount And an audit trail entry records claimId, retainedAmount, releasedAmount, and linkage to Stripe chargeId/refundId And no additional funds beyond $A are captured during this operation
Stripe Reversal Retry with Exponential Backoff and Alerting
Given a reversal attempt for hold H returns a transient error (HTTP 5xx or network timeout) When the retry policy executes Then the system retries the reversal up to 5 times with exponential backoff delays approximately 1m, 2m, 4m, 8m, 16m with ±10% jitter And the same idempotency key is used for all retries to prevent duplicate financial impact And on eventual success, status transitions to "Released" and the borrower status API updates within 1 minute And on final failure, status is set to "Release Delayed", an operational alert is sent to on-call, and the borrower sees a message including the next retry ETA
Idempotent Processing and Audit Trail Integrity
Given duplicate triggering events arrive (e.g., repeated return confirmations, duplicate Stripe webhooks, or job re-runs) When the system processes events for hold H under concurrent conditions Then at most one reversal or capture is executed on Stripe for H And the platform state machine for H performs a single state transition per logical event And the audit trail contains exactly one "reversal_initiated" record per logical event with a correlationId, and all duplicates are logged as "ignored_duplicate" And a daily reconciliation job at T+1 day verifies H’s final financial outcome against the platform ledger and Stripe; on mismatch > $0.01, a compensating action is scheduled and an alert is raised
Real-Time Borrower Status and ETA Visibility
Given a borrower with hold H whose release pathway has started (immediate, buffered, or claim) When the borrower opens the reservation details screen or calls GET /holds/{holdId}/status Then the API responds within 500 ms with fields: holdId, currentState, nextAction, etaTimestamp, amountHeld, amountToRelease, amountRetained, and reason And the UI receives a push update within 2 seconds of any state change (releasing, partially_released, released, release_delayed) And timestamps are in ISO 8601 UTC and consistent with audit log entries
Milestone-Based Hold Reduction
"As a new user, I want clear milestones to reduce my deposit holds so that I can build trust quickly."
Description

Guides new users through clear, actionable steps to reduce deposit holds, including ID verification, completing the first booking on time, adding a backup payment method, and obtaining organizer/HOA endorsement. Presents a progress tracker and contextual tips in onboarding and checkout, shows the impact of each milestone on deposit amounts and reversal speed, and updates trust tier eligibility in real time upon completion. Includes localized, accessible UI, email/push notifications for milestone opportunities, and rate limits to avoid spam.

Acceptance Criteria
Progress Tracker Displays Milestone Impacts in Onboarding and Checkout
Given a new user with no milestones, When they open onboarding or checkout, Then a progress tracker lists ID Verification, First On-Time Booking, Backup Payment Method, Organizer/HOA Endorsement with current status and next-best CTA. Given current baseline deposit and reversal speed are configured, When the tracker renders, Then each milestone displays its exact deposit reduction (amount and percent) and reversal speed change based on configuration and user state. Given the user completes any milestone, When the completion event is processed, Then the tracker, checkout deposit preview, and trust tier badge update within 2 seconds and reflect recalculated amounts and speeds. Given a milestone is disabled by policy or unavailable in the user’s region, When the tracker renders, Then the milestone is hidden and total potential reduction recalculates accordingly.
ID Verification Milestone Applies Configured Hold Reduction
Given the ID provider returns Verified, When the result is received, Then the system marks the milestone complete and applies the configured hold_reduction_percent to deposit computations. Given the ID provider returns Pending or Failed, When rendering deposit preview, Then no reduction is applied and the milestone shows actionable retry guidance. Given the milestone completes, When trust tier recomputes, Then the new tier is displayed in UI within 2 seconds and exposed via API within 5 seconds. Given the reduction is applied, When auditing, Then logs include user ID, old/new deposit, reduction percent, rule version, and timestamp.
First On-Time Booking Milestone Triggers Reduction
Given pickup grace <= 15 minutes and return grace <= 10 minutes are configured, When the user’s first booking completes within grace windows, Then mark the milestone complete and apply the configured reduction to future deposits and reversal speeds. Given the first booking is canceled or violates grace windows, When evaluating the milestone, Then it remains incomplete and no reduction applies. Given the milestone completes, When the user starts a new checkout session, Then the deposit preview and reversal time reflect the reduction consistently across web and mobile.
Backup Payment Method Milestone Affects Deposit and Reversal Speed
Given the user opens the milestone detail, When viewing, Then show the exact before/after deposit and reversal time impact based on configuration. Given the user adds a valid, verified backup payment method, When confirmation succeeds, Then mark the milestone complete and apply the configured reduction and reversal speed improvement. Given the backup method is removed or becomes invalid, When recalculating, Then revoke the milestone and remove its reductions with an explanatory banner at next checkout.
Organizer/HOA Endorsement Updates Trust and Holds
Given an organizer endorses the user in the same HOA/group, When the endorsement is saved, Then mark the milestone complete, apply the configured hold reduction, update trust tier, and display a verification badge. Given the endorsement expires or is revoked, When the change is processed, Then remove the reduction immediately and notify the user. Given multiple endorsements exist, When calculating reduction, Then apply only the single highest applicable endorsement benefit and prevent stacking.
Milestone Notifications With Rate Limiting
Given a user becomes eligible for a milestone, When eligibility is detected, Then send a single email and a single push notification per milestone with localized content and clear impact summary. Rate limits: Given limits are configured to max 1 per channel per 24 hours and max 3 per channel per rolling 7 days per milestone, When triggers exceed limits, Then suppress additional notifications and record the suppression event. Given the user has opted out of marketing but not transactional, When sending notifications, Then deliver only transactional reminders and respect opt-out flags.
Localization and Accessibility of Milestone UI
Given the user’s locale preference is supported, When viewing onboarding and checkout milestones, Then all strings are localized and currency, date, and time formats match the locale; missing translations fall back to English with telemetry. Given a right-to-left locale, When rendering, Then layout mirrors correctly and the progress tracker and CTAs remain readable and navigable. Accessibility: Given WCAG 2.1 AA, When tested with screen reader and keyboard-only, Then all milestone components are operable, focus order is logical, contrast >= 4.5:1, and status changes are announced via ARIA live regions.
Lender Deposit Controls
"As a lender, I want control over minimum deposits on my items so that I feel protected without deterring good borrowers."
Description

Provides lenders with item-level and portfolio-level settings to define minimum deposit floors, category-specific rules, and strict modes for high-value or frequently mishandled items. Displays predicted borrower-specific holds in the listing dashboard, with guardrails enforcing platform policy bounds and preventing discriminatory configurations. Resolves conflicts between lender floors and platform caps with clear messaging and recommended adjustments. Includes versioned policy storage, change history, and safe defaults to minimize borrower drop-off.

Acceptance Criteria
Item-Level Minimum Deposit Floor Validation
Given an existing item When the lender sets a minimum deposit floor and clicks Save Then the system validates the value against platform bounds (min ≤ value ≤ cap) and blocks saving with an inline error if out of range And if valid, the value is saved, the effective item policy preview updates, and an audit entry with user, timestamp, old→new values is recorded And the input enforces currency formatting and rounding to the smallest currency unit
Portfolio and Category Rule Defaults and Inheritance
Given a lender updates a portfolio-level rule for a category (e.g., Power Tools) with floor X and default strict-mode state When a new item is created in that category Then the item inherits the category defaults unless explicitly overridden during creation And when an existing item without an override is edited after the rule change, it reflects the updated category defaults And items with existing overrides remain unchanged And a bulk-apply action lets the lender propagate new category rules to selected items with a confirmation that shows item count and impact summary And new lenders with no settings get platform safe defaults applied automatically upon first listing
Strict Mode for High-Value or Frequently Mishandled Items
Given an item is flagged by the lender to use strict mode or the category rule enables strict mode When strict mode is enabled Then the effective minimum deposit floor becomes the strict floor configured by the lender, constrained by platform cap And the effective floor used for pricing is max(item floor, category floor, strict floor when enabled, platform minimum) and ≤ platform cap And the UI displays a visible Strict badge on the item settings and listing dashboard preview And strict mode cannot be saved if it would violate platform policy bounds, with an explanatory error shown
Predicted Borrower-Specific Holds Display in Listing Dashboard
Given a borrower with trust tier T and reliability score R When the lender views the item in the listing dashboard or uses the borrower simulator Then the UI shows the predicted hold amount and expected reversal window derived from T, R, and the lender's effective policy And the prediction updates within 1 second after any lender policy change (floor/strict) and matches backend computation within ±0.01 in display currency And a tooltip explains components (base, floor, cap, strict) without exposing borrower PII beyond tier and reliability
Conflict Resolution Between Lender Floors and Platform Policy Caps
Given a lender enters a floor below the platform minimum or above the platform cap When attempting to save Then saving is blocked and a message shows the allowed range and a recommended value within bounds And a one-click Apply Recommended action sets the recommended value and saves successfully And the API returns a 422 with code POLICY_CONFLICT and includes allowed range and recommended value And if the conflict arises from category vs item rules, both sources are highlighted with a preview of the resolved effective floor
Guardrails Against Discriminatory Configurations
Given lender-configurable rules allow only approved borrower attributes (trust tier, reliability, completed transactions) When the lender attempts to target disallowed attributes or proxies (e.g., name, photo, gender, race, age, non-service-area ZIP) Then the UI prevents configuration with a clear policy error and links to policy docs And the API rejects such inputs with 400 and code POLICY_PROHIBITED_ATTRIBUTE, logging an admin-visible reason And no UI control exposes disallowed targeting fields, and effective policy checks block disparate holds based on prohibited proxies
Versioned Policy Storage, Change History, and Rollback
Given versioned storage for lender deposit policies When any create/update/delete occurs Then a new immutable version is created with sequential ID, author, timestamp, and field-level diff And bookings reference and persist the policy version effective at booking time And lenders can view at least the last 50 versions with diffs and metadata and export history as CSV And rollback to a prior version creates a new version referencing the source and is blocked if it violates current platform bounds And policy history is retained for at least 24 months
Risk & Compliance Safeguards
"As a platform admin, I want guardrails on deposit holds and identity checks so that we stay compliant and reduce fraud risk."
Description

Implements identity verification and payment authentication flows proportionate to hold size and risk (e.g., Stripe Identity, SCA), enforces regional preauthorization duration limits, and ensures PCI-compliant handling of payment data. Adds fraud detection signals (velocity checks, device fingerprinting, IP/geolocation anomalies), a rules-based decision layer for escalations, and a manual review queue for outliers. Provides comprehensive audit logs, data retention policies, and admin tooling to override holds with justification. Includes monitoring/alerts for preauth failures, expirations, and reversal delays.

Acceptance Criteria
Tiered Identity Verification Triggering
- Given a borrower initiates a booking and (trustTier <= 2 OR reliabilityScore < 0.85 OR holdAmount >= configured.idv_hold_threshold), When checkout advances to payment, Then Stripe Identity (document + liveness) is required before preauthorization. - Given a borrower with trustTier >= 4 AND reliabilityScore >= 0.95 AND fraudRiskScore < configured.idv_stepup_threshold AND holdAmount < configured.idv_hold_threshold, When booking proceeds, Then ID verification is not prompted. - Given ID verification completes, When results are returned, Then cardholder name fuzzy-match >= 0.92 to verified name, liveness passes, accepted docType in {passport, driver_license, state_id}, and a verification token (no images) is stored with TTL per policy. - Given ID verification fails, times out, or is canceled, When user attempts to confirm booking, Then confirmation is blocked, failure reason shown, up to 3 retries allowed within 24 hours, and an audit log entry is created.
Strong Customer Authentication Enforcement
- Given the card issuer is in EEA/UK OR the issuer requests 3DS, When preauthorization is attempted, Then a 3DS2 challenge is initiated and must succeed before the hold is placed. - Given a soft decline indicating SCA is required, When exemption is not applicable, Then the system retries with a 3DS challenge once within 5 minutes and logs the outcome. - Given a permitted exemption (TRA or low-value) is available and supported by the issuer, When preauthorization is attempted, Then the exemption is requested and the result (approved/overridden) is recorded. - Given SCA fails or is canceled, When the user retries, Then a maximum of 2 additional SCA attempts are allowed before the booking is canceled and the user is notified. - Then the SCA outcome per attempt (challenge, frictionless, exemption, fail) and related identifiers are stored for audit.
Regional Preauthorization Duration Management
- Given renter region and card network define a maximum hold duration L, When placing a deposit hold, Then the hold expiration is set to <= L and stored with region/network metadata. - Given a booking spans beyond L, When T = 24 hours before expiration, Then the system attempts to refresh the preauthorization (or create a new hold) using consent captured at checkout; on failure, the booking is paused and the user is notified. - Given a preauthorization is refreshed successfully, Then the previous hold is released within 10 minutes and both events are logged with traceability. - Then the system prevents holds from remaining active past expiration; any expired hold is auto-marked and reversal is initiated immediately with status tracking.
Fraud Detection, Decisioning, and Manual Review Escalation
- Given a booking attempt occurs, When signals are evaluated (accountAgeDays, failedPaymentVelocity, successfulHoldVelocity, deviceFingerprint consistency, IP geolocation distance from profile address, proxy/VPN detection, email/phone reputation), Then a riskScore 0–100 is computed and stored. - Given riskScore >= configured.block_threshold, When checkout continues, Then the booking is blocked, user receives a generic denial, and a fraud case is created. - Given riskScore is between configured.stepup_threshold and configured.block_threshold, When checkout continues, Then step-up actions (SCA and/or IDV) are required and must pass to proceed. - Given rules flag "manual_review" OR step-up fails with high risk, When the attempt is logged, Then a case is queued to Manual Review including all signals and Stripe references; SLA: decision within 4 business hours; outcome (approve/deny/require-extra) recorded.
Admin Override Controls with Justification
- Given a deposit hold is active or pending, When an admin with role >= FinanceManager initiates an override (increase/decrease/cancel hold), Then a justification text (min 20 chars) and reason code must be provided before execution. - Given an override request changes the hold by more than configured.dual_control_threshold, When submitted, Then a second approver is required before the change is applied. - Then the audit record includes before/after amounts, actor and approver IDs, timestamps (UTC), IP/device, reason code, free-text justification, and related booking/risk case IDs; the record is immutable and searchable.
PCI Compliance, Audit Logging, and Data Retention
- Then no raw PAN, CVC, or track data is persisted or logged; only Stripe tokens/PM IDs are stored; application and infrastructure logs are automatically redacted of card data. - Given CI and weekly production scans, When secret/PAN detection runs, Then zero occurrences of card data in code, configs, or logs are reported; any finding fails the pipeline and pages on-call. - Then audit logs for IDV, SCA, preauths, refreshes, reversals, rule decisions, and admin overrides include actor, subject, action, outcome, timestamp (UTC), request ID, and are write-once; retention is 24 months. - Then PII retention enforces provider-token storage for IDV artifacts, honors user deletion requests within 30 days, applies region overrides (e.g., GDPR), and logs each deletion/retention decision.
Monitoring and Alerts for Preauth and Reversal Events
- Given preauthorization attempts, When failure rate > 5% over a 15-minute window OR absolute failures > 20 within 15 minutes, Then an alert is sent to on-call via PagerDuty/Slack with a runbook link. - Given holds approaching expiration, When any hold is < 12 hours from expiration without a scheduled refresh OR the count of <24h-to-expire holds exceeds 50, Then an alert is created for operations. - Given deposit reversals are pending, When any reversal exceeds 24 hours since booking end OR > 2 hours since a successful capture release call, Then an alert is triggered and affected users receive a status notification. - Then a dashboard shows real-time metrics (holds placed/refreshed/expired, reversal time-to-release p95, SCA success rate, manual review SLA) with 90-day retention of time series.

Mutuals Graph

See safe, privacy‑aware connections—shared buildings, mutual vouchers, and prior successful handoffs—so you know how you’re linked. Converts skeptics by revealing real neighborhood trust paths and helps lenders approve faster.

Requirements

Privacy-Preserving Mutuals Graph Engine
"As a cautious neighbor, I want to see how I’m connected to someone I’m booking with so that I can decide quickly if I feel safe lending or borrowing."
Description

Implement a backend service that builds and maintains a privacy-aware graph of relationships between neighbors based on shared building membership, mutual vouchers, and prior successful handoffs. The service exposes a query to return connection types and counts between a lender and borrower (direct and first-degree paths, max depth 2), without revealing sensitive PII (no unit numbers, no full names for intermediaries). Only minimal, aggregated metadata is returned (e.g., “2 mutual vouchers,” “same building,” “1 prior handoff”), with recency windows and data minimization. The engine integrates with booking events to update edges in real time upon successful handoffs, with idempotent writes to prevent duplicate edges. It provides an authorization layer to ensure users only see connections they are entitled to, and a schema compatible with future sources (e.g., HOA verification) while honoring opt-outs.

Acceptance Criteria
Aggregated Connections Query Without PII
Given lender L and borrower B are authenticated and have shared building membership, 2 mutual vouchers via intermediaries, and 1 prior successful handoff within configured recency windows When L requests connections via GET /mutuals?lenderId={L}&borrowerId={B} Then the response contains only aggregated fields relevant to enabled edge types (no raw entity details) and at minimum includes: sameBuilding (boolean), mutualVoucherCount (integer), priorHandoffCount (integer) And mutualVoucherCount = 2 And sameBuilding = true And priorHandoffCount = 1 And no PII is returned: no unit numbers, no full names for intermediaries, no intermediary identifiers, and no building identifiers
Max Depth-2 Path Inclusion
Given voucher paths exist between L and B at depths 2 and 3 (e.g., L—voucher—I1—voucher—B and L—voucher—I2—voucher—J—voucher—B) When L queries connections to B Then mutualVoucherCount includes only paths up to depth 2 and excludes any path with depth > 2 And the count does not double-count the same intermediary across multiple equivalent paths And the response reveals no intermediary identities
Real-Time Graph Update on Successful Handoff Event
Given a booking with id X between L and B transitions to status handoff_success at time t When the event is emitted to the engine Then an edge of type handoff between L and B is upserted within 5 seconds of t And a subsequent query for (L,B) reflects priorHandoffCount increased by 1
Idempotent Edge Upsert for Duplicate Events
Given the engine receives N ≥ 2 identical handoff_success events for booking id X between L and B When events are processed in any order and with potential concurrency Then only one handoff edge is stored for booking id X And priorHandoffCount increases by at most 1 And repeated queries return a stable count
Authorization and Entitlement Enforcement
Given user U is authenticated as lender L When U requests connections for pair (L,B) Then 200 OK is returned with only aggregated fields Given user C (not L or B) attempts the same request Then the request is denied with 403 Forbidden And unauthenticated requests receive 401 Unauthorized And building-based connections are only returned when both L and B are members of the same building and visibility is permitted by policy
Recency Windows and Data Minimization Applied
Given configuration sets voucherRecencyWindowDays = 730 and handoffRecencyWindowDays = 540 And vouchers and handoffs exist both inside and outside these windows for L and B When L queries connections for (L,B) Then mutualVoucherCount includes only vouchers with createdAt within the last 730 days And priorHandoffCount includes only handoffs with occurredAt within the last 540 days And the response omits raw timestamps and raw identifiers for vouchers, handoffs, and buildings
Opt-Out Honored and Future Source Extensibility
Given user M has opted out of being used as an intermediary for mutual connections When L queries connections to B where the only available path uses M Then mutualVoucherCount does not include paths that rely on M Given a new edge type hoa_verification is enabled by configuration When both L and B are verified by the same HOA Then the response includes an aggregated field hoaVerifiedSame = true And no HOA name, address, or identifier is returned And if the feature flag is disabled, the field is omitted
Mutuals Visualization UI
"As a prospective lender, I want a clear visual summary of how I’m connected to a requester so that I can assess trust at a glance without digging through profiles."
Description

Deliver a responsive UI component that displays connection badges and counts (shared building, mutual vouchers, prior handoffs) on user profiles and inside the booking approval modal. The component emphasizes clarity and privacy: it shows connection types, totals, and high-level labels with tooltips explaining each signal, but hides intermediary identities unless explicitly consented. It supports compact and expanded states, a “Why am I seeing this?” explainer, and a link to manage privacy settings. It degrades gracefully when no connections exist and supports accessibility (ARIA labels, keyboard nav) and theming to match Sharehood’s design system.

Acceptance Criteria
Profile: Compact Mutuals Badges (Responsive)
Given a viewer opens a user profile with mutuals data loaded, When the viewport width is <640px, Then display exactly three badges labeled “Shared building”, “Mutual vouchers”, and “Prior handoffs” with their respective counts in a single row. Given mutuals counts are provided by the API, When the component renders, Then the counts shown on each badge match the payload exactly. Given the viewport width is ≥640px, When the component renders, Then badges align to the left with design-system spacing and wrap as needed without overlap or truncation of counts. Given any badge is focusable or hovered/tapped, When a user interacts, Then the badge shows a non-blocking tooltip trigger affordance without shifting layout. Given network latency or slow data, When the profile loads, Then a skeleton or loading shimmer appears in place of badges and is removed once data arrives, without content jumping outside the badge container.
Booking Approval Modal: Expanded Mutuals Panel
Given a lender opens the booking approval modal for a requester, When the modal loads, Then a Mutuals panel is visible with an expand/collapse control defaulting to expanded on desktop and collapsed on mobile. Given the panel is expanded, When rendered, Then it shows the three connection types with counts and concise descriptions that fit within the modal width without horizontal scrolling. Given the panel is collapsed, When the user activates the expand control via click or keyboard (Enter/Space), Then the panel expands and focuses the first interactive element within the panel. Given the modal is closed and re-opened, When the Mutuals panel renders, Then it restores the default expand state based on device breakpoint. Given mutuals data updates while the modal is open, When new data is received, Then the counts update in place without losing focus or resetting the expand/collapse state.
Privacy: Redact Intermediary Identities Without Consent
Given mutual connections include intermediaries without explicit consent, When the component renders, Then it shows only high-level labels and counts and does not display names, avatars, or links of those intermediaries. Given some intermediaries have granted explicit consent, When the panel is expanded, Then only those consented identities appear and are labeled with non-sensitive display names per policy. Given no intermediaries have consented, When the panel is expanded, Then no identities are shown and the counts remain visible with a note that identities are hidden for privacy. Given a user revokes consent in privacy settings, When the component next renders, Then previously visible identities are no longer displayed and only high-level counts remain. Given any redacted area is present, When users attempt to navigate via keyboard or screen reader, Then no hidden identity content is exposed via accessibility APIs.
Explainers: Tooltips and "Why am I seeing this?"
Given a user hovers, focuses, or taps a badge, When the tooltip is invoked, Then it shows a concise explanation of that signal (e.g., what counts as a prior handoff) without naming any individuals and is dismissible via Esc or blur. Given a user activates the “Why am I seeing this?” link, When the explainer opens, Then it presents a short rationale, links to the Trust & Privacy policy, and includes a “Manage privacy settings” link that routes to the app’s privacy settings screen. Given the explainer is open, When the user presses Esc or activates the close control, Then focus returns to the element that triggered the explainer. Given the device is touch-only, When a tooltip is opened by tap, Then a second tap outside or on the badge dismisses it without obstructing other controls. Given the modal context, When the explainer is opened within the booking modal, Then it opens as an in-modal sheet without causing the underlying modal to scroll.
Empty State: No Connections Detected
Given the API returns zero for all connection types, When the component renders, Then it shows a neutral empty state with the message “No mutuals yet” and an info icon, and does not render any badges. Given the empty state is shown on a profile, When viewed on mobile and desktop, Then the component occupies minimal vertical space and does not cause layout shifts > 16px compared to the state with badges. Given the empty state is shown in the booking approval modal, When the modal loads, Then the Mutuals section is present with the empty message and no interactive controls for expansion. Given data later indicates non-zero connections, When the component re-renders, Then the empty state is replaced with badges without requiring a page reload. Given localization is applied, When the empty state renders, Then the message is sourced from i18n strings and fits within the container without truncation.
Accessibility: ARIA, Keyboard, and Contrast
Given a keyboard-only user navigates the component, When tabbing, Then focus moves to each badge, the expand/collapse control, the “Why am I seeing this?” link, and the manage-privacy link in a logical order with visible focus indicators. Given a badge receives focus, When a user presses Enter or Space, Then the tooltip opens and is announced by screen readers; pressing Esc closes it and returns focus to the badge. Given the expanded panel is open, When a user presses Shift+Tab from the first focusable element or Tab from the last, Then focus remains trapped within the modal until it is closed. Given a screen reader user, When focusing on a badge, Then the control exposes an accessible name like “Shared building: 2 connections. Learn more.” via ARIA labels. Given the component renders in light and dark modes, When checked with a color contrast analyzer, Then text and iconography meet WCAG 2.1 AA (≥4.5:1 for text; ≥3:1 for graphical objects).
Theming: Design Tokens and High‑Contrast Mode
Given the Sharehood design system tokens are loaded, When the component renders, Then all colors, typography, spacing, and radii are derived from tokens with no hard-coded values. Given the user toggles between light and dark themes, When the component re-renders, Then badge backgrounds, text, and icons adapt to theme tokens without losing contrast or readability. Given the OS high-contrast mode is enabled, When the component renders, Then essential information (labels, counts, focus states) remains visible and distinguishable, and decorative elements are suppressed if required by the token set. Given a brand override theme is applied, When regression tests run, Then the component inherits updated tokens without overflow, clipping, or misalignment at common breakpoints (375px, 768px, 1024px). Given CSS prefers-reduced-motion is enabled, When the component shows tooltips or expands panels, Then motion is minimized to opacity/transform with reduced duration or disabled per accessibility guidelines.
Trust Score with Explainability
"As a lender, I want a simple trust score with reasons so that I can justify quick approvals while understanding what influenced the recommendation."
Description

Compute a lightweight trust index derived from available signals (e.g., prior successful handoffs with either party, mutual vouchers count and recency, shared building presence), using transparent, configurable weights. Present the score alongside an explanation that lists contributing factors and their relative impact, avoiding any sensitive or protected-class inferences. The scoring service must be deterministic, audited for bias, and adjustable via feature flags, with versioning of weight sets and backfill scripts. The UI surfaces the score only with its rationale to prevent black-box decisions.

Acceptance Criteria
Deterministic Scoring Consistency
Given a fixed borrower–lender pair with identical input signals and the same weight_set_version When the trust-score API is invoked 100 times across two service instances within 24 hours Then every response contains the exact same numeric score and byte-identical ordered explanation payload Given the same inputs and version When the scoring service is restarted and the computation is re-run Then the SHA-256 checksum of (score + explanation JSON) matches the previously stored checksum Rule: No randomness is used in the scoring path; observed variance across identical requests equals 0.0
Explainability Completeness and Math Integrity
Given a computed trust score When the API responds Then the explanation includes for each factor: factor_name, raw_value, normalized_value, weight, signed_contribution, percent_of_total, and is sorted by absolute signed_contribution descending And the response includes weight_set_version and data_completeness in [0,1] And the sum of signed_contribution equals the score within ±0.01 Rule: Explanation omits any protected/sensitive attributes and does not infer them
Signal Coverage and Configurable Weights
Given supported signals: prior_successful_handoffs_count, mutual_vouchers_count, mutual_vouchers_recency_days, shared_building_boolean When an admin configures weights Then each signal weight accepts values in [-2.0, +2.0] with step 0.1 and passes schema validation Given a signal is missing for a request When the score is computed Then the factor’s normalized_value is set to 0 (neutral), reason="missing" is recorded in explanation, and the result remains deterministic Given a signal weight is set to 0 When the score is computed Then the factor is excluded from both score and explanation
Versioning and Backfill of Weights
Given a new weight_set_version is created When it is published Then it receives an immutable version_id and audit metadata (author, timestamp, change_diff) is stored When a version is promoted to active Then historical scores for the last 180 days are backfilled via an idempotent job producing records with prior_score, new_score, version_from, version_to for ≥99% of eligible rows And failures are retried with exponential backoff up to 5 times and surfaced in job status Given the backfill is run with dry_run=true When it completes Then no scores are updated and a delta report is produced
Feature-Flag Rollout and Rollback
Given an environment and cohort rule When the feature flag trust_weights_version is set to version X for that cohort Then 100% of subsequent requests from that cohort use version X and responses echo version X When the flag is rolled back to version W Then all new requests reflect version W within 2 minutes without downtime Rule: Multiple cohorts may use different versions concurrently with zero cross-cohort leakage as verified by logs
UI Coupling: Score Always With Rationale
Given the Mutuals Graph renders a trust score for a borrower–lender pair When the component loads Then it displays the score value together with the top 3 highest-impact factors and their signed contributions And the user can expand within one action to view all factors Given the API response lacks an explanation When the UI handles the response Then the score is not rendered, a non-blocking "Explanation unavailable" state is shown, and a telemetry event trust_score_explanation_missing is emitted Rule: Automated UI tests fail if a score node renders without an explanation node
Sensitive Attribute Exclusion and Compliance Audit
Given the scoring and explanation modules When CI static checks run Then any reference to fields labeled protected/sensitive (e.g., race, gender, age, religion, disability, income) fails the build When production request/response payloads are stored for audit Then PII is redacted, records are hash-chained for tamper evidence, and retained for 180 days When the quarterly compliance audit executes Then it confirms protected attributes are absent from inputs and explanations, feature usage complies with data policy, and any detected proxy variables on approved offline datasets with correlation >0.3 are blocked from weight sets
Consent & Privacy Controls
"As a privacy-conscious neighbor, I want control over which of my connections are visible so that I can participate without oversharing personal details."
Description

Provide user-facing controls to opt in/out of appearing as a mutual connection and to granularly toggle which signals are shareable (shared building, vouchers, prior handoffs). Include clear onboarding notice, per-signal consent, and a privacy center link wherever mutuals are shown. Ensure compliance with data deletion requests (remove edges, purge caches), limit data retention windows for stale edges, and maintain an auditable consent log. By default, apartment/unit numbers are never displayed; building-level affiliation is generalized to the property name only.

Acceptance Criteria
Onboarding Per-Signal Consent Prompt
- Given a signed-in user with no prior consent settings, When they open any view that would display mutuals for the first time, Then they see a blocking modal titled "Choose what to share" containing three independent toggles: Shared Building, Mutual Vouchers, Prior Successful Handoffs. - And each toggle is Off by default and requires explicit opt-in to turn On. - And the modal includes a plain-language summary for each signal and a link labeled "Privacy Center" that navigates to the privacy settings screen. - And if the user continues without opting in, Then no mutuals signals are displayed and a non-intrusive inline prompt offers "Manage consent". - And the user's selections persist to their account and remain consistent across devices within 5 minutes of change.
Global Opt-In/Out of Appearing as Mutual Connection
- Given a user navigates to Privacy Center, When they view Mutuals Visibility settings, Then a master "Appear as a mutual connection" toggle is present. - And the default state is Off until the user explicitly enables it. - And When the master toggle is Off, Then the user never appears as a mutual to others, regardless of per-signal toggles, and no new edges are resolvable. - And When the master toggle is On, Then the user appears only for the specific signals they have enabled and only where the counterpart has enabled the same signals. - And changes to the master toggle take effect in live views and mutuals APIs within 15 minutes.
Mutuals Display Honors Dual Consent and Hides Unit Numbers
- Given viewer A and subject B, For each signal S in {Shared Building, Mutual Vouchers, Prior Successful Handoffs}, When both A and B have the master visibility On and S toggled On, Then S is shown in the mutuals UI for A about B; otherwise S is not shown. - And apartment/unit numbers are never displayed; building affiliation is shown only as the property name (e.g., "Parkside Apartments") without unit identifiers. - And Mutuals API and UI payloads do not contain unit_number or any field that encodes unit-level info. - And automated tests assert absence of unit-level data in API responses and DOM text by checking for null/omitted fields and by rejecting patterns like "#", "Apt", or "Unit" tied to addresses.
Privacy Center Link on All Mutuals Surfaces
- Given any surface that displays mutuals (graph panel, profile mutuals, booking card hints, tooltips), When the surface is rendered, Then a visible, focusable control labeled "Privacy & Consent" is present and navigates to Privacy Center. - And the control is accessible to screen readers with an appropriate accessible name and has a contrast ratio ≥ 4.5:1. - And activating the control routes within the app without 404/500 errors and loads the Privacy Center within 2 seconds on a 3G fast network profile.
Data Deletion Request Removes Edges and Purges Caches
- Given a verified data deletion request from a user, When the request is approved, Then all mutuals graph edges and derived indices associated with that user's identity are suppressed from display within 15 minutes and hard-deleted from primary stores within 30 days. - And all related caches (in-memory, CDN, search indices) are purged within 15 minutes and do not return the user's edges thereafter. - And the user receives a confirmation within 24 hours indicating suppression and the final deletion date. - And the consent log records "delete_request" and "delete_complete" entries with UTC timestamps while retaining only minimal identifiers per policy.
Stale Edge Retention Limits and Scheduled Purge
- Given mutuals edges with no reinforcing activity, When an edge is stale for 12 months (no new voucher validation, handoff, or building residency verification), Then the edge is removed by a scheduled job and no longer appears in any UI or API. - And the purge job runs at least daily, logs counts of removed edges, and invalidates relevant caches within 15 minutes. - And admin metrics expose the number of stale edges purged and the next scheduled run time.
Auditable Consent Log Integrity and Export
- Given any change to consent or visibility, When a user toggles the master or any per-signal control or submits a deletion request, Then an append-only consent log entry is created with user_id, signal_key, action (opt_in|opt_out|visibility_on|visibility_off|delete_request|delete_complete), source (onboarding|privacy_center|api), and UTC timestamp. - And log entries are immutable; edits create a new entry and do not modify previous entries. - And an authorized admin can export a per-user consent history as CSV within 60 seconds for a 10k-row dataset. - And integrity checks verify the sequence is complete and strictly ordered by timestamp for the user's changes.
Lender Approval Assist
"As an organizer managing shared gear, I want mutuals and trust cues in the approve screen so that I can decide faster and keep the schedule moving."
Description

Embed the mutuals summary and trust score within the booking approval flow, providing a one-screen decision aid with contextual actions (Approve, Request Info, Decline). Allow lenders to set a personal auto-approve threshold (e.g., auto-approve when trust score ≥ X or when a prior handoff exists) with safe defaults and guardrails. Record the decision inputs for analytics and provide a quick link to message the borrower when signals are borderline. Integrate seamlessly with existing calendar and deposit hold flows to reduce friction and speed approvals.

Acceptance Criteria
One-Screen Approval Aid Shows Mutuals and Trust Score
Given a lender views a pending booking request on mobile or desktop When the approval screen loads Then the trust score (0–100) with a descriptive label and info tooltip is visible above the fold And the mutuals summary shows counts for shared buildings, mutual vouchers, and prior successful handoffs And data freshness is indicated as a timestamp if older than 24 hours or “Just updated” when under 5 minutes And no personally identifiable details of third parties are revealed (counts and relationship labels only) And the above content loads within 1.5 seconds at the 95th percentile on a 4G connection And the UI meets WCAG 2.1 AA for color contrast, focus order, and screen reader labels
Contextual Decision Actions in Approval Flow
Given trust information has loaded or gracefully timed out When the lender reviews the request Then Approve, Request Info, and Decline actions are visible, enabled, and keyboard-accessible And selecting Approve triggers a confirmation sheet summarizing dates, deposit hold amount, and pickup window And selecting Decline requires a reason selection (with an “Other” free-text option) and notifies the borrower And selecting Request Info opens the in-app message composer pre-addressed to the borrower with editable templated prompts And all actions complete within 2 seconds at the 95th percentile and return the user to the booking thread with a status banner
Auto-Approve Threshold Configuration with Guardrails
Given a lender opens Approval Settings When they configure auto-approve rules Then they can select conditions: trust score ≥ X (0–100) and/or prior successful handoff exists And the default suggested threshold is 80 and is clearly marked as recommended And thresholds below 60 trigger a warning and require explicit confirmation And settings persist per lender account and can be edited or disabled at any time And changes take effect for new requests within 1 minute
Auto-Approval Execution and Guarded Failure Handling
Given an incoming booking meets the lender’s auto-approve rules When the system evaluates the request Then the booking is auto-approved, the Stripe deposit hold is created, the calendar is blocked, and notifications are sent to both parties And the lender receives an in-app and email summary of the auto-approval with the matched rule And if the deposit hold fails, auto-approval is aborted, the borrower is prompted to update payment, and the lender is asked to review manually And all outcomes are recorded in the audit log with a correlation ID
Decision Inputs Logged for Analytics
Given any decision is made (Approve, Request Info, Decline, Auto-Approve) When the action completes Then the system records: trust score at decision time, mutuals counts, matched rule (if any), timestamps, anonymized user and item IDs, and action channel And logs are available in analytics within 5 minutes of the event And logs exclude third-party personally identifiable information and adhere to data retention policy
Borderline Signals Surface a Message Shortcut
Given a lender-defined threshold exists When a borrower’s trust score is within 10 points below the threshold or a prior handoff exists but the score is below threshold Then a “Message borrower” shortcut is shown with suggested prompts (e.g., pickup timing, ID verification) And activating the shortcut opens the composer with the booking context attached And the shortcut is not shown if the score meets or exceeds threshold or if messaging is disabled for either party
Seamless Calendar and Hold Integration Without Overlaps
Given the lender approves (manually or auto) a booking that may overlap existing holds or bookings When the approval action runs Then the smart pickup window auto-adjusts to avoid overlaps according to existing rules And the calendar reflects the final booking times immediately and prevents double-booking at the resource level And exactly one deposit hold is created per booking; duplicate holds are not created on retries And on decline or expiry, any pending hold is released in Stripe within 5 minutes and the calendar slot reopens
Graph Performance & Caching
"As an on-the-go neighbor, I want trust info to load instantly so that I can complete a booking without waiting."
Description

Guarantee low-latency graph lookups by implementing read-optimized indices, pairwise result caching, and event-driven cache invalidation on new handoffs or consent changes. Target p95 < 200 ms for borrower–lender queries within a neighborhood-size shard. Include circuit breakers, rate limiting, and graceful fallbacks (e.g., show base profile without mutuals) under load or partial outages. Provide observability dashboards with latency, hit rate, and error metrics, and alerts tied to SLO breaches.

Acceptance Criteria
Shard-Scoped Borrower–Lender Mutuals Lookup p95 Latency
Given a production-like dataset within a single neighborhood-size shard When borrower–lender mutuals lookups are executed at steady load Then end-to-end request latency p95 <= 200 ms and error rate < 0.5% And no single request exceeds 1000 ms And the service returns HTTP 200 for successful responses
Pairwise Mutuals Cache with Event-Driven Invalidation
Given pairwise borrower–lender mutuals results are cached When the same pair is requested repeatedly during steady state Then cache hit rate >= 80% and median response time <= 120 ms Given a new accepted handoff or a consent change for either party When the event is emitted and consumed Then all affected cache entries are invalidated within 1 second And subsequent lookups reflect the change within 1 second
Read-Optimized Indices for Mutuals Query Path
Given the persistence layer for graph data When running EXPLAIN/TRACE on mutuals lookup queries Then query plans use read-optimized indices for all joins/filters And zero full-table/collection scans occur on the hot path And p95 database execution time for the query <= 80 ms
Circuit Breaker Triggers and Base-Profile Fallback
Given downstream dependencies show >= 5% error rate or p95 latency > 400 ms over 60 seconds When the circuit breaker policy evaluates Then the circuit opens within 10 seconds and halts downstream calls And client responses return base profile without mutuals within <= 250 ms And no 5xx is returned for requests served via fallback
Per-User and Per-IP Rate Limiting for Mutuals Endpoint
Given a user account or IP exceeds 60 requests per minute to the mutuals endpoint When additional requests arrive in the same window Then respond with HTTP 429 and a Retry-After header set to the reset time And compliant users continue to receive p95 <= 200 ms responses And rate-limit events are logged with user identifier, IP hash, and count
Observability Dashboards and SLO Alerts for Graph Service
Given the service is deployed to production Then dashboards display p50/p95/p99 latency, cache hit rate, error rate, circuit state, and rate-limit counts per shard And an SLO is defined: p95 < 200 ms for shard-scoped borrower–lender lookups with 99% monthly compliance And alerts page on-call when 10-minute rolling p95 > 200 ms or error rate > 1% for 5 consecutive minutes And dashboards and alert runbooks are linked from the service README
Graceful Degradation Under Load and Partial Outage
Given a synthetic load of 3x normal traffic with 20% dependency timeouts for 10 minutes When serving borrower–lender mutuals lookups Then >= 99% of requests succeed, applying base-profile fallback where necessary And no process OOM/restarts occur; work queues remain below configured high-water marks And the system auto-recovers to normal mode within 60 seconds after dependencies recover
Graph Integrity & Abuse Prevention
"As a platform owner, I want safeguards against fake connections so that the mutuals feature remains trustworthy and resistant to gaming."
Description

Protect the mutuals graph from manipulation by enforcing edge provenance (only verified events create edges), deduplicating entities (e.g., buildings), and validating vouchers (unique, non-reciprocal spam limits, cooldowns, and recency caps). Detect anomalous patterns (sudden voucher bursts, circular voucher rings) and route to a review queue with admin tooling to disable suspect edges. Prevent disclosure of sensitive locations by generalizing addresses and requiring building verification via existing tenancy proofs where available.

Acceptance Criteria
Edge Provenance Enforcement
Given a request to create a graph edge without a verified source event (successful handoff, verified building membership, or validated voucher), When the API receives the request, Then the edge is rejected with HTTP 403 and an audit log entry is created. Given a verified source event, When the edge is created, Then the edge stores immutable provenance fields (source_type, source_id, event_timestamp, verifier_id) and a verified_provenance=true flag. Given an existing edge, When a client attempts to modify provenance fields, Then the operation is rejected with HTTP 409 and no changes are persisted. Given a graph read operation, When edges are returned, Then edges lacking verified_provenance=true are excluded from user-facing results.
Building Entity Deduplication
Given a new building submission, When the normalized address matches an existing building by exact postal normalization or geohash7+street_number match, Then the submission is merged into the existing building and no duplicate node is created. Given two building records with fuzzy score >= 0.9 or within 20 meters and same street number, When deduplication runs, Then a single canonical building_id remains and all edges are reattached to it with no loss. Given a merge occurs, When the operation completes, Then an audit record is stored (merge_from_ids, merge_to_id, actor_id, timestamp) and is visible in admin. Given a user queries the graph after a merge, When reading building-based edges, Then no duplicate edges are returned.
Voucher Validation Rules
Given user A issues a voucher to user B, When an existing active voucher from A to B exists within the last 90 days, Then the new voucher is rejected with HTTP 409. Given user A received a voucher from user B within the last 30 days, When A attempts to issue a voucher to B, Then the action is blocked to prevent reciprocal vouchers within the 30-day window. Given any user attempts to issue vouchers, When the count exceeds 3 in 24 hours or 10 in 7 days, Then subsequent vouchers are blocked until the cooldown elapses. Given a voucher older than 180 days, When computing mutuals edges, Then that voucher does not contribute to edge creation. Given a voucher is created, When validation passes, Then the voucher is stamped with issuer_id, recipient_id, issued_at, expires_at, and validation_rules_version.
Anomaly Detection and Routing
Given a user issues more than 5 vouchers in 10 minutes or more than 20 vouchers in 24 hours, When detection runs (every minute), Then the account and associated vouchers are flagged and routed to the review queue within 60 seconds. Given a cycle of vouchers of length 3–6 where >=80% were issued within 48 hours, When graph analysis runs hourly, Then the cycle is flagged and all edges created from those vouchers are marked suspect=true. Given an account creates >3 building memberships for unverified buildings within 24 hours, When detection runs, Then the memberships are flagged and prevented from creating edges. Given an item is flagged, When the review queue receives it, Then a notification is posted to the admin channel and an audit event is created.
Review Queue and Admin Edge Controls
Given a suspect edge in the review queue, When an admin selects Disable Edge, Then the edge is removed from user-facing graph queries within 60 seconds and its status changes to disabled with reason and admin_id recorded. Given an edge was disabled, When an admin selects Restore Edge, Then the edge reappears in user-facing queries and the restoration is logged. Given the review queue, When filtering by rule_type, account_id, time window, or building_id, Then the result set updates within 500 ms server processing time. Given bulk selection of >=50 suspect edges, When Disable is confirmed, Then all selected edges are disabled in a single transaction and the operation either commits all or none.
Address Generalization and Privacy
Given a mutuals graph response includes building location, When returned to clients, Then the address is generalized to block-level (street name + block number) and coordinates are rounded to >=100m precision with no unit/apartment numbers included. Given an API consumer requests raw address or precise coordinates via any endpoint, When the user is not an authorized admin, Then the API omits or redacts those fields. Given a UI view of mutuals, When rendering building context, Then it displays generalized address text and a privacy badge indicating location is obfuscated. Given server logs and analytics pipelines, When storing location fields, Then only generalized forms are persisted for non-admin contexts.
Building Verification via Tenancy Proofs
Given a user submits third-party tenancy proof, When the token is valid, Then the building node is marked verified and building-based edges for that user become active immediately. Given no valid tenancy proof is provided, When a user attempts to create a building-based edge, Then the edge creation is blocked and a prompt for verification is returned. Given a building verification older than 12 months, When daily jobs run, Then affected edges are suppressed until the user re-verifies. Given a verification attempt fails, When retried after cooldown of 24 hours, Then the system allows a new attempt and logs the previous failure reason.

Safe Mode

For high‑value gear, enable an extra ring: live selfie match at pickup, tighter windows, and double confirmation on return. Keeps premium items circulating by adding assurance only when risk is highest.

Requirements

Safe Mode Toggle per Item
"As an owner of high-value gear, I want to enable Safe Mode on specific items so that bookings include extra verification and protections without adding friction to my standard listings."
Description

Add a per-item Safe Mode toggle visible to owners during listing creation and editing, and to organizers in bulk management. When enabled, the platform enforces Safe Mode workflows for that listing: live selfie match at pickup, tightened pickup/return windows, variable deposit holds, and double confirmation on return. The UI displays a Safe Mode badge on search results, item pages, and booking checkout so borrowers understand the added assurance. The API exposes a safe_mode flag and associated policy parameters for mobile and web clients. Existing listings default to off and can be migrated without breaking current bookings. Enabling Safe Mode must remain compatible with the live calendar and overlap auto-adjustments, and surfaces any conflicts to the owner before publishing. Analytics track activation rate, conversion impact, and incident rate to quantify benefit.

Acceptance Criteria
Owner Toggles Safe Mode in Listing Creation
Given an owner is creating a new listing When the owner enables the Safe Mode toggle and saves as draft or publishes Then the listing persists with safe_mode=true and policy parameters copied from the active Safe Mode policy And the form displays a Safe Mode badge preview and a summary of requirements (selfie match, tighter windows, variable deposit, double confirmation) And pre-publish validation checks the listing’s calendar; any conflicts caused by tightened pickup/return windows are listed with booking_id and timestamps And if conflicts exist, Publish is blocked until the owner selects “Apply to new bookings only” or resolves conflicts And if no conflicts, the listing publishes and appears in search within 60 seconds with the Safe Mode badge And overlap auto-adjustments remain enabled for all new bookings
Existing Listings Migration Defaults and Booking Preservation
Given the Safe Mode schema migration is executed in production When the migration completes Then 100% of existing item records have safe_mode=false and no change to current policy/availability fields And 100% of future bookings retain their original pickup/return windows and workflows And zero booking cancellation events are emitted due to the migration And application error rate does not increase above baseline by more than 0.1% during the migration window And an audit job reports 0 discrepancies between total items and items with an explicit safe_mode flag
Organizer Bulk Management Safe Mode Toggle
Given an organizer with permissions selects N items in bulk management When the organizer sets Safe Mode = On and confirms Then the system updates safe_mode=true for all eligible items and returns a summary: updated_count, skipped_count (with reason), failed_count (with error) And items with existing future bookings are updated such that Safe Mode applies only to new bookings unless the organizer opts to apply to all future bookings and acknowledges conflicts And each item change is logged with actor_id, item_id, from_value, to_value, and timestamp And the bulk action is idempotent; re-running the same selection produces zero additional changes
Safe Mode Operational Enforcement at Pickup and Return
Given a booking for an item with safe_mode=true When the borrower attempts pickup Then the app requires a live selfie capture and matches it to the borrower’s profile photo with a similarity score ≥ policy.threshold before allowing checkout And pickup is permitted only within the policy.pickup_window; attempts outside are blocked with a descriptive error And a Stripe deposit hold equal to policy.deposit_amount is placed before checkout completes When the borrower returns the item Then the system requires double confirmation: borrower marks returned and owner/organizer confirms receipt within policy.confirmation_window And the deposit hold is released only after both confirmations succeed; otherwise an incident is opened and the hold is retained or escalated per policy
Safe Mode Badge Display on Search, Item, and Checkout
Given an item with safe_mode=true is visible to a borrower When the item appears in search results Then a Safe Mode badge renders on the result card with an accessible label describing added verification and tighter windows And when the borrower opens the item page, the badge renders above the fold with a tooltip explaining requirements And during checkout, a Safe Mode summary is shown before confirmation and cannot be dismissed without acknowledgement And for items with safe_mode=false, no Safe Mode badge or copy is displayed on any surface
API Safe Mode Flag and Policy Parameters
Given a client calls GET /items/{id} When the item has safe_mode=true Then the response includes safe_mode=true and safe_mode_policy fields: selfie_required, pickup_window_minutes, return_window_minutes, deposit_amount, double_confirmation_required And when updating via POST/PUT /items with safe_mode set, only the owner or an authorized organizer receives 200; unauthorized requests receive 403 And changing safe_mode from false to true does not modify existing booking objects; new bookings inherit the active policy at time of booking And the OpenAPI schema and developer docs include the new fields and example payloads
Analytics: Activation, Conversion, and Incident Tracking
Given analytics collection is enabled When Safe Mode is toggled on or off for an item Then an event safe_mode_toggled is emitted with item_id, actor_role, from_value, to_value, and timestamp And booking events for items include safe_mode=true/false to enable downstream attribution And a daily job computes metrics: activation_rate, conversion_delta (booking_rate_safe_mode − booking_rate_non_safe_mode), and incident_rate (incidents per 100 bookings) by category and neighborhood And a dashboard surfaces these metrics with ≤24-hour data freshness and supports filtering by date range and item category
Live Selfie Match at Pickup
"As a borrower, I want a quick selfie match at pickup so that the owner trusts the handoff and I can access premium items without lengthy ID checks."
Description

Implement a live selfie verification step at pickup for Safe Mode bookings. The borrower is prompted to grant camera access and capture a liveness-checked selfie that is matched to their verified profile photo using a trusted facial similarity service with anti-spoofing. Matching runs in near real time with clear pass/fail feedback; results are recorded with timestamp and booking ID. On match failure or user opt-out, provide a fallback manual verification flow for the owner with photo capture and acknowledgement. All biometric processing follows consent and data minimization principles; embeddings are stored securely with strict retention and access controls. The flow must function on iOS, Android, and mobile web, degrade gracefully for low connectivity, and never block standard bookings. Owners see a green check in the handoff screen when verification succeeds; support can review verification artifacts for disputes.

Acceptance Criteria
Camera Permission and Liveness-Only Selfie Capture
- Given a Safe Mode booking at pickup, When the borrower begins verification and is prompted for camera permission, Then the app uses the front camera and blocks uploads from gallery, screenshots, or files. - Given camera permission is granted, When capture starts, Then liveness detection runs and prevents submission until a live face is detected per anti-spoofing signal. - Given no face or spoof is detected, When the borrower attempts to submit, Then the app shows an actionable error and allows up to 3 retries within the pickup window.
Near-Real-Time Match and Borrower Feedback
- Given a liveness-passed selfie, When sent to the facial similarity service, Then a match is considered Pass when similarity score >= 0.85 and Fail when < 0.85. - Given processing has started, Then the borrower receives a definitive Pass/Fail result within 5 seconds at the 95th percentile and a loading state is displayed until completion. - Given a Pass result, Then the pickup flow advances automatically and the owner’s handoff screen displays a green verification check within 2 seconds.
Failure or Opt-Out Triggers Manual Verification
- Given a Fail result, denied camera access, or the borrower declines biometric consent, When the pickup continues, Then the system automatically offers the owner a manual verification flow without blocking the booking. - Given the manual flow, When the owner captures required photos (borrower at pickup and item at handoff) and acknowledges, Then the booking is marked Verified (Manual) with reason recorded (Fail/Opt-Out/Permission Denied). - Given manual verification completes, Then timestamp, booking ID, owner ID, and photo artifacts are stored and linked to the booking for later review.
Consent, Data Minimization, and Security Controls
- Given first biometric use in a session, When verification is initiated, Then the borrower must be shown a consent screen describing purpose, storage, retention, and controls, and must explicitly opt in before processing. - Given selfie processing, Then only embeddings and minimal necessary artifacts are stored; raw images are automatically purged within 24 hours unless preserved for an active dispute. - Given stored artifacts, Then they are encrypted in transit (TLS 1.2+) and at rest (AES-256 or equivalent), access is limited by least-privilege RBAC, and all access is auditable.
Low Connectivity Graceful Degradation
- Given network latency > 800 ms or upload fails, When the borrower captures a selfie, Then the app queues the encrypted payload locally and displays Pending Verification status. - Given a queued verification, Then the app retries with exponential backoff for up to 30 minutes or until connectivity resumes, whichever is first. - Given retries expire, Then the system prompts the owner to complete manual verification without blocking the pickup and removes queued data after 24 hours if unused.
Cross-Platform Coverage and Safe Mode Scoping
- Given iOS, Android, and mobile web platforms, Then the verification flow functions with equivalent UX and passes device compatibility tests covering at least 90% of active devices by traffic. - Given a standard (non–Safe Mode) booking, When the pickup flow is opened, Then no biometric prompts or permissions are requested and the booking path is unaffected. - Given Safe Mode is disabled on an item, Then selfie verification is not available or shown for that item’s bookings.
Owner and Support Visibility with Audit Trail
- Given any verification attempt, When it completes, Then the system logs booking ID, borrower ID, timestamps, result (Pass/Fail/Manual), confidence score, platform, and network quality, without storing unnecessary PII. - Given a Pass result, Then the owner’s handoff screen shows a green check with the verification timestamp; on Fail/Manual, shows appropriate status and next steps. - Given a dispute is opened, When a support agent with the correct role reviews the booking, Then they can view verification artifacts and export them via a signed URL that expires within 10 minutes.
Tightened Pickup/Return Windows
"As a borrower of a high-value item, I want tighter pickup and return windows with reminders so that I can plan precisely and avoid penalties or missed handoffs."
Description

When Safe Mode is enabled, reduce booking pickup and return windows to precise time slots with configurable buffers and grace periods. The scheduler auto-adjusts for overlaps, travel time, and owner availability, sending proactive reminders and countdowns to both parties. Late arrivals trigger policy-driven actions such as owner prompts, rebooking options, or deposit hold escalation. Windows must respect time zones, daylight savings, and organizer-defined building access rules. The UI clearly communicates the narrowed windows during checkout and in calendars, with single-tap confirm buttons. Integrate with existing live calendar logic to prevent conflicts and to inject Safe Mode buffers without breaking previously scheduled bookings.

Acceptance Criteria
Safe Mode Slot Generation: Buffers and Grace
- Given Safe Mode is enabled for an item with configured pickup/return slot lengths, buffers, and grace periods, When a borrower views available times for a chosen date, Then the system displays discrete time slots aligned to the configured slot length and within the owner's availability. - Given a borrower selects a Safe Mode pickup slot, When the booking is created, Then the system blocks the slot plus the configured pre- and post-buffers on the live calendar. - Given a Safe Mode booking exists, When the pickup or return window opens, Then the booking enters a Window Open state and the grace period countdown begins. - Given a Safe Mode booking with grace period G, When the borrower arrives within G minutes after the slot start, Then the booking is processed without late policies being triggered. - Given Safe Mode is disabled for the item, When a borrower views times, Then standard (non-Safe Mode) pickup/return windows are presented.
Scheduler Auto-Adjust: Overlaps, Travel Time, Owner Availability
- Given existing bookings and injected buffers for both owner and borrower, When a new Safe Mode booking is requested, Then only slots with no overlap against any booking or buffer for either party are offered. - Given travel-time estimation is enabled, When either party has another commitment adjacent to a candidate slot, Then the scheduler ensures at least estimated travel time plus configured buffer separates the commitments. - Given the owner manually edits availability creating a potential conflict, When the system revalidates the calendar, Then any conflicting Safe Mode slot is flagged and compliant alternatives are suggested without modifying previously confirmed bookings. - Given a previously scheduled non–Safe Mode booking exists, When Safe Mode buffers are injected for a new booking, Then the existing booking’s times are neither shortened nor shifted.
Time Zones, DST, and Building Access Compliance
- Given the owner and borrower are in different time zones, When a Safe Mode slot is selected, Then each party sees times in their local time zone and all server-side times are stored in UTC. - Given a booking spans a daylight saving time change, When the window opens, Then it opens at the correct absolute time and buffer/grace durations remain accurate to the minute. - Given organizer-defined building access rules (e.g., 09:00–17:00 with a 12:00–13:00 closure), When generating Safe Mode slots, Then only slots fully contained within allowed access windows are offered. - Given building access rules are updated after a booking is made, When a conflict with the booked slot is detected, Then both parties are notified and compliant alternatives are proposed; no auto-cancel occurs unless required by policy.
UI: Narrowed Windows Visibility and One-Tap Confirms
- Given Safe Mode applies to a booking, When the borrower reaches checkout, Then the UI prominently displays narrowed pickup/return slot times along with buffer and grace details before payment. - Given a Safe Mode booking is confirmed, When either party opens their calendar, Then the event is labeled Safe Mode and shows precise slot times, buffer blocks, and current state (e.g., Confirmed, Window Open, Late). - Given the pickup window opens, When the borrower taps Confirm Pickup Now, Then the status updates to Picked Up within 2 seconds and the owner’s view reflects the change without manual refresh. - Given the return window opens, When the owner taps Confirm Return after inspection, Then the status updates to Returned and any deposit hold is released per policy. - Given accessibility requirements, When the booking screen is read by assistive technologies, Then all Safe Mode labels and confirm buttons have accessible names and hints.
Proactive Reminders and Live Countdowns
- Given a Safe Mode booking exists, When time reaches 24 hours before each slot (if applicable), Then both parties receive a reminder with localized times, a deep link to the booking, and an option to confirm or reschedule. - Given any Safe Mode slot, When time reaches 2 hours, 15 minutes, and at window open, Then the app displays a live countdown and sends push/in-app notifications; if push fails, email/SMS is sent when enabled. - Given a reminder notification includes an action, When the user taps the action, Then the app deep-links to the booking and records the confirmation/reschedule event with user ID and timestamp. - Given time zone and DST differences, When reminders and countdowns are presented, Then displayed times match the recipient’s local time and the countdown is accurate to the minute.
Late Arrival Policies and Deposit Hold Escalation
- Given a Safe Mode booking with grace period G and policy P, When the borrower has not confirmed arrival by G minutes after slot start, Then policy P triggers presenting the owner options to extend, rebook, or mark no-show. - Given the owner selects Extend by X minutes, When confirmed, Then a temporary extension is created that respects buffers and avoids conflicts; both parties are notified of the new cutoff. - Given the owner selects Rebook, When alternatives are generated, Then only compliant slots within the policy-defined window are offered and acceptance updates the booking without losing audit history. - Given the owner selects No-Show or no response occurs within the policy timeout, When policy dictates deposit escalation, Then the deposit hold is escalated per policy and the borrower is notified with appeal instructions. - Given any policy action occurs, When viewing the booking timeline, Then an immutable audit log shows the actor, action, and timestamp.
Double Confirmation on Return
"As an owner, I want both parties to confirm the returned condition so that deposits are released automatically when things look good and retained when issues arise."
Description

Require both borrower and owner to confirm item return and condition for Safe Mode bookings. The return flow guides users through photo capture of key angles, optional quick checklist for common wear points, and a condition rating. If both parties agree, the system auto-releases the deposit hold; if there is a mismatch, it opens a dispute with all artifacts attached and extends the hold per policy. The flow supports asynchronous confirmations when parties are not co-located, and records timestamps, location context, and device metadata for traceability. Integrate with notifications to nudge pending confirmations and with Stripe to control deposit release or capture.

Acceptance Criteria
In-Person Return: Matched Confirmation Releases Deposit
Given a Safe Mode booking with an active deposit hold and status "Return Pending" And borrower and owner are authenticated And their recorded locations at submission are within 50 meters When borrower submits return confirmation with the required photo set, optional checklist response, and a condition rating And owner submits return confirmation for the same booking within the same session with the exact same condition rating And neither party flags any checklist discrepancy Then the booking status updates to "Returned-Confirmed" And the system triggers deposit hold release And both parties receive a success notification And an audit log entry records both confirmations
Asynchronous Return: Owner Later Confirms
Given a Safe Mode booking with an active deposit hold and status "Return Pending" When the borrower submits return confirmation remotely (not co-located) Then the booking status updates to "Owner Confirmation Pending" And the owner is notified immediately via configured channels And if the owner has not confirmed by Policy.OwnerConfirmNudge1 hours, a first nudge is sent And if still unconfirmed by Policy.OwnerConfirmNudge2 hours, a second nudge is sent And the deposit hold remains active until owner confirmation or dispute opening And upon owner confirmation with matching condition and no discrepancies, the booking status updates to "Returned-Confirmed" and the deposit hold is released
Mismatch Triggers Dispute and Hold Extension
Given borrower and owner submit return confirmations for the same booking When their condition ratings differ or any checklist item is marked differently by the parties Or any party flags damage with accompanying photos Then the system creates a dispute case linked to the booking And attaches all artifacts (both photo sets, ratings, checklist responses, timestamps, location context, and device metadata) And updates booking status to "Dispute Open" And extends the deposit hold by Policy.HoldExtensionDuration And notifies both parties of the dispute with a link to the case
Photo Evidence, Metadata, and Optional Checklist
Given a Safe Mode item with a defined return photo template When a party enters the return flow Then the UI requires capture/upload of all required angles from the template before allowing submission And each photo meets or exceeds Policy.MinReturnPhotoResolution And the optional checklist of common wear points is visible and can be completed in ≤ Policy.ChecklistMaxSteps taps And if the checklist is skipped, the system records "Checklist Skipped" with user role and timestamp And the submission stores timestamps, location context (lat, lon, accuracy), device model, OS version, app version, and IP address And if location permission is denied, the submission records "Location Unavailable (permission denied)"
Condition Rating Capture and Agreement Definition
Given the return flow requires a condition rating on a 1–5 scale (1=Poor, 5=Like New) When both parties submit their ratings Then agreement is defined as identical numeric ratings and zero conflicting checklist marks And if agreement criteria are met, the return is eligible for automatic deposit release And if agreement criteria are not met, the system treats the return as a mismatch and opens a dispute
Notifications and Escalations for Pending Confirmations
Given a Safe Mode booking awaiting the other party’s confirmation When the pending state starts Then the system schedules nudges per Policy.OwnerConfirmNudge1 and Policy.OwnerConfirmNudge2 (or borrower equivalents) And sends in-app and push/email notifications via configured channels And escalates to support or admin queue after Policy.EscalationThreshold if still unconfirmed And all notification events are recorded in the audit log with timestamps and delivery outcomes
Stripe Deposit Hold Control and Error Handling
Given a booking with an active deposit hold on Stripe When automatic release is triggered by matched confirmations Then the system calls Stripe to release the hold using an idempotency key unique to the booking And marks the release as Pending until Stripe confirms success And upon success, the hold amount is set to zero and a Stripe event is recorded in the audit trail And on transient failure, the system retries per Policy.StripeRetryBackoff up to Policy.StripeMaxRetries And if retries are exhausted, the booking remains in "Return Confirmed - Payout Pending", both parties are informed, and support is alerted And when a dispute opens, the system extends or captures the hold per Policy.DisputeHoldAction and records the Stripe action and outcome
Variable Deposit Holds
"As an organizer, I want configurable deposit holds for premium items so that risk is covered appropriately without deterring trustworthy borrowers."
Description

Allow Safe Mode listings to specify deposit policies per item, including fixed amounts or smart amounts calculated from item value, borrower history, and incident rates. Integrate with Stripe to create, extend, and release authorization holds in compliance with network rules, with graceful handling of SCA, retries, and partial captures for damages. Display deposit amounts and rules transparently during checkout and in receipts. Provide admins with configuration controls and reporting on average hold amounts, capture rates, and impacts on conversion. Ensure deposit logic aligns with tightened windows and dispute outcomes.

Acceptance Criteria
Fixed Deposit on Safe Mode Listing
- Given a Safe Mode listing has a fixed deposit configured in the listing currency, When a borrower reaches the payment step, Then a Stripe authorization hold for the exact configured amount is created prior to booking confirmation, and the booking is blocked if the authorization fails. - Given the booking is canceled before pickup start, When the cancellation is confirmed, Then the hold is released immediately and a release confirmation is shown and emailed to the borrower. - Given the pickup window is tightened or shifted earlier/later by the system, When the new window still falls within the original authorization validity, Then no new authorization is created; otherwise a new authorization is created and the old one is released without double-holding the borrower. - Given a fixed deposit is configured, Then the hold amount on Stripe, the UI, and the receipt match exactly (no rounding discrepancies) and are displayed in the listing currency with correct symbol. - Given network limits on authorization validity, When the booking spans beyond the validity window, Then the system automatically schedules an extension or re-authorization within card network and Stripe rules and notifies the borrower if re-auth is required.
Smart Deposit Calculation from Risk Signals
- Given a Safe Mode listing uses Smart Deposit, When an eligible borrower initiates checkout, Then the system calculates a deposit using item value, borrower history score, and incident rate according to the configured formula, bounded by admin-set min/max limits. - Given identical inputs (item value, borrower score, incident rate, currency), When the calculation is invoked, Then the computed deposit is deterministic and auditable with inputs and output logged with a correlation ID. - Given any required signal is missing or the calculation service errors, When checkout proceeds, Then a configurable safe fallback deposit (e.g., default or fixed) is used and surfaced to the user with a non-technical message; the error is captured in logs/monitoring. - Given Smart Deposit is used, When the final amount is presented at payment, Then the UI also shows a brief explanation (e.g., “Based on item value and your borrowing history”) and the exact amount before the user authorizes payment. - Given admin-configured currency rules, Then the smart deposit amount is rounded per currency minor units and never below zero or above the configured maximum.
Authorization Lifecycle Compliance with Stripe and Networks
- Given a booking is confirmed, When the deposit authorization is created, Then the authorization uses Stripe’s Payment Intents/Setup Intents per best practice and is compliant with card network pre-authorization rules (no capture at auth time). - Given the pickup window auto-adjusts in Safe Mode, When the adjustment would push beyond the current auth’s validity, Then the system extends the auth where allowed or performs a seamless re-authorization; the borrower is prompted for any required action (e.g., SCA) and the booking remains in a consistent state. - Given the booking ends without damages, When return is confirmed, Then the authorization is released within 0–5 minutes and no capture occurs. - Given an authorization expires unexpectedly (issuer shortens validity), When Stripe notifies via webhook, Then the system attempts one re-authorization and alerts the borrower to re-verify if needed; if re-authorization fails, the booking is paused and pickup blocked until resolved. - Given idempotency is required, When creating, extending, or canceling authorizations, Then idempotency keys are used to prevent duplicate holds or releases, and ledger records reconcile 1:1 with Stripe events.
SCA and Retry Handling for Deposit Holds
- Given the card/issuer requires SCA, When the borrower authorizes the deposit, Then a 3DS challenge is presented, and booking confirmation occurs only after successful SCA; on failure, the booking is not confirmed and the borrower receives a clear retry prompt. - Given a soft decline or network error occurs during authorization, When retry logic triggers, Then up to 2 automatic retries with exponential backoff are attempted within 2 minutes, preserving idempotency and without creating duplicate holds. - Given a hard decline code (e.g., do_not_honor) is returned, When authorization fails, Then the borrower is prompted to add a different payment method or contact issuer; the attempt is logged with non-PCI metadata only. - Given SCA was previously satisfied for the same intent within the allowed window, When a re-authorization is required due to window shift, Then the system reuses exemption/whitelisting where compliant or re-prompts for SCA only if mandated by the issuer. - Given accessibility requirements, When SCA flows render, Then they pass WCAG AA for focus order, labels, and error messaging.
Partial Capture for Damages and Remainder Release
- Given an incident is recorded, When an admin captures funds for damages, Then the system allows a partial capture up to the authorized amount, and prevents capturing above the remaining hold. - Given a partial capture succeeds, When the capture completes, Then the remaining authorization amount is released within 0–5 minutes and the borrower receives an itemized receipt showing damage description, captured amount, and released remainder. - Given capture is attempted after auth expiry, When Stripe returns an error, Then the system guides the admin to initiate a new charge with explicit consent and records a link to the evidence/dispute workflow. - Given a capture occurs, When a dispute is later resolved in the borrower’s favor, Then the captured funds are refunded and the audit trail links the dispute outcome to the original capture. - Given tax regulations, When capturing for damages, Then tax application follows admin configuration (taxable or non-taxable) and is reflected correctly on the receipt.
Transparent Display in Checkout, Booking, and Receipts
- Given a Safe Mode item at checkout, When the deposit step is reached, Then the exact deposit amount, policy type (Fixed or Smart), and key rules (hold timing, release timing, capture conditions) are displayed before the user authorizes payment. - Given the smart deposit amount changes due to updated risk signals before authorization, When the payment step reloads, Then the new amount is shown and requires explicit user confirmation before proceeding. - Given a booking is active, When the user views Booking Details, Then the current hold status (Authorized, Extended, Re-authorizing, Captured, Released) and amounts are shown in real time. - Given a booking completes without capture, When the receipt is generated, Then it clearly states that a deposit hold of X was released on date/time, with the Stripe last4 and authorization reference. - Given a capture occurs, When the receipt is generated, Then it shows captured amount, reason code, evidence link, and released remainder (if any).
Admin Configuration and Reporting
- Given listing settings, When an admin edits a Safe Mode item, Then they can select deposit policy (Fixed or Smart), set fixed amount and currency, or configure smart parameters (weights, min, max, default fallback) and save with validation. - Given platform analytics, When viewing Deposit Reports, Then admins can see average hold amounts, capture rates, and conversion impact segmented by item category, Safe Mode status, and date range, with CSV export. - Given audit needs, When an admin reviews a booking, Then a full deposit lifecycle log is available (timestamps for auth, extensions, re-auths, captures, releases; Stripe IDs; user prompts; error codes). - Given role-based access, When a non-admin tries to access deposit configurations or reports, Then access is denied and logged. - Given feature flags, When deposit policies are updated, Then changes can be rolled out by cohort/region and are reversible without data loss.
Safe Mode Audit Trail
"As a support agent, I want a complete Safe Mode audit trail so that I can resolve disputes quickly and fairly with verified evidence."
Description

Create an immutable audit trail for Safe Mode bookings that aggregates selfie verification results, pickup and return timestamps, location context, photos, confirmations, and system decisions. Store records with tamper-evident identifiers and enforce least-privilege access for support and compliance review. Provide export capability for dispute resolution and legal requests, and define retention schedules that satisfy privacy requirements while preserving necessary evidence. Surface a concise timeline view in the booking details for owners and borrowers so they can see what happened when without exposing sensitive data unnecessarily.

Acceptance Criteria
Audit Event Capture Across Safe Mode Lifecycle
Given a Safe Mode booking exists When booking confirmation, selfie verification, pickup check-in, pickup photo upload, pickup confirmation, return initiation, return confirmation, and any system decision occur Then an audit entry is persisted for each event within 2 seconds of the event commit And each entry includes booking_id, event_type, actor_role, event_timestamp (ISO 8601 UTC), source, decision/outcome, location_context, media_refs with content_hash, and correlation_id And optional fields are explicitly null when unavailable And retrieving by booking_id returns entries in chronological order with a monotonic sequence to break timestamp ties And creating the same event with the same correlation_id is idempotent and does not create duplicates
Tamper-Evident Identifiers and Integrity Proof
Given an audit entry is stored Then it is assigned an immutable audit_id and content_hash and links to previous_hash per booking to form a verifiable chain When any stored field is altered outside the write path Then chain verification returns invalid and identifies the first compromised link When verifying integrity for a booking with up to 1,000 entries Then verification completes within 500 ms at p95 And a read-only proof object (algorithm, root_hash, created_at) is available and included in exports
Least-Privilege Access and Purpose-Based Controls
Given roles owner, borrower, support_agent, and compliance_officer When a user without support_agent or compliance_officer role requests full audit details Then access is denied with 403 and an access log entry is created When a support_agent requests full audit data Then they must provide purpose_of_access and pass JIT approval, and only policy-permitted fields are returned; media blobs are redacted unless an approved case flag is present When owner or borrower view booking details Then only redacted timeline fields are returned with sensitive fields omitted (no selfies, no precise geolocation, no full-resolution media) And every read of audit data is logged with subject_id, role, purpose, timestamp, booking_id, and result and is retrievable via admin audit log
Concise Timeline View in Booking Details (Redacted)
Given an owner or borrower opens a Safe Mode booking details page When the timeline renders Then it displays a chronological list of key events with human-readable labels and timestamps And selfie verification is shown only as status and confidence bracket (pass/fail; low/med/high) without the selfie image or full score And location is shown as neighborhood/geofence name only without exact coordinates And pickup/return photos display low-resolution thumbnails; full-resolution access requires elevated review flow and is not directly accessible And the timeline loads within 1.0 second at p95 for bookings with up to 50 events
Export for Disputes and Legal Requests
Given a support_agent initiates an export for a specific booking When selecting export type Dispute or Legal Then the system generates a signed ZIP bundle containing JSON data, a human-readable PDF summary, integrity proof, and relevant media per policy And Dispute exports redact biometric images and precise coordinates, replacing with content_hash and coarse location; Legal exports include full content as permitted by policy And a one-time, access-controlled download link is produced that expires after 7 days And export completion occurs within 60 seconds at p95 for bundles up to 1 GB or streams progressively for larger sets And export creation is recorded in the audit log with requester, purpose, and booking_id
Retention, Purge, and Legal Hold Enforcement
Given retention policies of 24 months for audit entries, 30 days for biometric selfies, and 90 days for media unless a legal hold or dispute is active When a record reaches its TTL without an active hold Then the data are purged and non-referenced blobs deleted, with the action logged And the audit chain remains verifiable via preserved metadata and hashes; accessing purged content returns 410 Gone with reason=retention_purge When a legal hold is applied to a booking Then deletions for covered data classes are suspended within 5 minutes and the suspension is logged; releasing the hold resumes scheduled purges And administrators can generate a policy report of items due for purge and exceptions; purge jobs are idempotent and retry-safe
Risk-Based Safe Mode Rules
"As an organizer, I want automatic Safe Mode enforcement based on risk signals so that high-value items stay protected without requiring manual setup every time."
Description

Introduce admin-configurable rules that auto-enable Safe Mode based on item value thresholds, borrower trust level, first-time borrower status, or recent incident patterns. Provide a rules UI with presets and simulation so organizers can see projected impact before publishing. Expose overrides at the item and booking level for edge cases, with change logs. The rules engine must evaluate synchronously during checkout to determine whether Safe Mode applies and which parameters to enforce (window length, deposit amount, verification steps). Include analytics to measure reduction in incidents and effect on conversion, enabling iterative tuning.

Acceptance Criteria
Synchronous Safe Mode Decision at Checkout
Given a borrower initiates checkout for any item When the rules engine evaluates applicable risk rules and overrides Then the engine returns a decision payload containing {safeModeEnabled, windowLengthMinutes, depositAmount, verificationSteps[], ruleVersion, rationale[]} within 300 ms at p95 and 1,000 ms at p99 And the decision is persisted with bookingId, itemId, borrowerId, timestamp, and ruleVersion And the checkout UI reflects Safe Mode status and parameters without an extra page load And an audit event 'safe_mode_decision_made' is emitted with the same payload
Admin Configures Risk Rules (Value, Trust, First-Time, Incidents)
Given an organizer with admin permissions opens the Rules UI When they select the 'High-Value Gear' preset and adjust conditions (item value >= configurable threshold, borrower trust tier <= selected tier, first-time borrower flag true, recent incidents for community >= N in the last M days) Then the UI validates all fields, displays a human-readable summary, and prevents save if any conflicts or missing values exist And upon saving as Draft, the rules are versioned and stored without affecting live decisions And upon Publish, the new rule version becomes active within 60 seconds and is displayed as the current version with effective timestamp And precedence is deterministic and visible: booking override > item override > published rules > presets (draft) And deactivation/rollback to a prior version is possible within the UI and takes effect within 60 seconds
Simulation Preview and Projected Impact Before Publish
Given a new or edited ruleset in Draft When the organizer runs Simulation against the last 90 days of bookings for their community Then the system returns within 2 minutes a report showing: percentage of bookings that would be in Safe Mode, projected change in incident rate (absolute and per 100 bookings), projected checkout-to-confirm conversion delta, and top drivers (conditions triggering) And the report lists the top 50 impacted items and borrowers by count with filters and allows CSV export And the Publish action remains disabled until at least one simulation has been completed on the current draft during the current session And the simulation parameters and results are stored with the draft version and timestamp
Item- and Booking-Level Overrides with Precedence
Given an organizer views an item or a booking When they create or edit an override to force Safe Mode On or Off, providing a reason and optional expiry datetime Then the override is validated (cannot set expiry in the past), saved, and takes effect immediately for that scope And booking-level override supersedes item-level override, which supersedes published rules And expired overrides auto-expire and no longer affect new decisions without manual cleanup And overrides are displayed inline wherever decisions are shown, including the rationale that an override was applied
Change Log and Audit Trail for Rules and Overrides
Given any create, edit, publish, rollback, or delete action on rules or overrides When the action is saved Then the system records an immutable audit log entry with timestamp, actor id, actor role, action type, target id, before/after JSON diff, reason/comment, and correlation ids (bookingId/itemId if applicable) And authorized users can view a chronological change log with filtering and export to CSV And unauthorized users cannot access the change log endpoints (403), and all access is logged
Enforcement of Safe Mode Parameters in Booking Flow
Given Safe Mode is applied to a booking with parameters windowLengthMinutes, depositAmount, verificationSteps=[live_selfie_match, double_return_confirmation] When the borrower proceeds through checkout, pickup, and return Then the booking windows are constrained to the specified length and reschedules respect the constraint And a deposit hold for the specified amount is placed via Stripe at checkout before confirmation; if the hold fails, confirmation is blocked with a clear error And at pickup, live selfie match must succeed within 3 attempts; failure blocks pickup and notifies the organizer And at return, double confirmation is required (borrower + owner/organizer) to complete the booking And telemetry events are emitted for each step with success/failure status
Analytics on Incidents and Conversion for Safe Mode Tuning
Given the analytics dashboard is opened with a selected time range and community When the organizer filters by Safe Mode On/Off and rule version Then the dashboard displays: incident rate per 100 bookings, incident severity distribution, checkout-to-confirm conversion rate, and pre/post comparisons for the selected period And metrics are refreshable with data latency <= 24 hours and are segmentable by borrower trust tier and first-time status And all charts and underlying aggregates can be exported to CSV, and figures match back-end queries within ±1%

Relist Cascade

Automatically reassigns a missed pickup to the next eligible borrower in a multi-stage queue. If the original window lapses or the borrower fails to check in, the item is instantly re-listed with compressed pickup windows and pre-approved backups. Keeps gear circulating, saves lenders time, and helps serious borrowers snag last-minute openings.

Requirements

Queue Orchestration Engine
"As an organizer, I want missed pickups to reassign automatically so that items keep circulating without my intervention."
Description

Build a concurrency-safe service that maintains an ordered, multi-stage borrower queue per item and atomically reassigns a booking when a pickup window lapses or a no-show is detected. Integrate with Sharehood’s live calendar to recompute and reserve the next pickup window in real time, honoring lender availability, HOA constraints, and existing bookings. Provide idempotent APIs and event hooks so other services (notifications, payments, analytics) can react to state changes. Handle race conditions, retries, and partial failures to ensure the item has exactly one active holder at any time.

Acceptance Criteria
Lapsed Window Auto-Reassignment
Given an item has an active booking with pickup window ending at time T and the borrower has not checked in by T When the current time reaches or exceeds T Then the engine atomically cancels the current booking and assigns the next eligible borrower in the queue And it recomputes the next pickup window using the live calendar while honoring lender availability, HOA constraints, and existing bookings And it reserves the recomputed window in the calendar within 3 seconds of lapse detection And it updates queue positions and booking states in a single transaction ensuring exactly one active holder for the item
No-Show Detection and Cascade Relist
Given a booking requires borrower check-in by windowStart + configured grace period G When the borrower does not check in by windowStart + G Then the engine marks the booking as NoShow and immediately reassigns the item to the next eligible borrower And it applies the configured pickup-window compression policy to the new assignment and records the policy applied in booking metadata And it completes reassignment and calendar reservation within 3 seconds of the missed check-in deadline
Single Active Holder Under Concurrency
Given multiple conflicting actions (e.g., lapse detection, manual cancel, reassignment API calls) target the same item concurrently When these actions are processed Then the engine guarantees that at most one booking is in Active state for the item at any time And conflicting transactions fail with a retryable conflict and do not create duplicate assignments And the item’s queue state uses monotonic versioning and the final committed version reflects exactly one reassignment
Idempotent Reassignment API
Given a client calls POST /items/{itemId}/reassign with an Idempotency-Key K When the client retries the same request one or more times due to timeouts or network errors Then exactly one reassignment is performed for K And all subsequent retries return the same response body and booking identifiers as the original execution without side effects And only one set of domain events is emitted for the operation keyed by K
Calendar Integration Honors Constraints
Given lender availability windows, HOA curfew constraints, and existing reservations on the live calendar When the engine computes the next pickup window for the next eligible borrower Then the selected window lies entirely within allowed availability and outside HOA curfew periods And it does not overlap existing bookings by more than 0 minutes and meets the configured minimum duration And if the first feasible window cannot be reserved atomically, the engine evaluates subsequent feasible windows; if none exist, it skips the borrower with reason NoFeasibleWindow and proceeds to the next
Partial Failures, Retries, and Compensation
Given a reassignment involves multiple steps (state update, calendar reservation, event publish) When a partial failure occurs after some steps succeed (e.g., state updated but calendar reservation fails) Then the engine completes the operation using retries with exponential backoff or compensates to a consistent state so that no orphaned Active assignment remains without a reserved window And it persists a recoverable record and surfaces a retryable status without duplicating assignments And after max retries, the booking is marked PendingRecovery and does not violate the single-active-holder invariant
Eligibility and Pre-Approval Enforcement
Given a queue contains multiple borrowers with varying eligibility attributes (e.g., pre-approval status, policy flags) When the engine selects the next borrower upon lapse or no-show Then it only considers borrowers with Eligible=true as of selection time and skips ineligible borrowers with recorded reason codes And the selection is deterministic per configured policy (e.g., FIFO among eligible backups) and the applied policy identifier is stored on the assignment And the engine proceeds through backups until a valid reassignment is committed or the queue is exhausted
Check-in and No-Show Detection
"As a borrower, I want clear check-in prompts and deadlines so that I don’t lose my spot unexpectedly."
Description

Implement borrower check-in workflows that confirm intent and arrival: time-based prompts (e.g., T-60/T-15 reminders), one-tap check-in, optional geofenced arrival confirmation, and lender QR verification. Define configurable grace periods and no-show rules; if check-in is missed or arrival is not verified within the window, trigger the cascade. Persist timestamps and proofs for auditability, and support lender manual overrides with reason codes. Integrate with the calendar and queue engine to transition states reliably.

Acceptance Criteria
Time-Based Check-In Prompts and One-Tap Check-In
- Given a confirmed pickup with a configured check-in window, When the time reaches T-60 and T-15 before window start, Then a reminder is queued and logged for each enabled channel and includes a deep link to the booking’s check-in screen. - Given the borrower opens the deep link during the check-in window, When they tap the check-in button, Then the booking transitions to "Checked-In (Intent Confirmed)" and a UTC timestamp is persisted. - Given the borrower attempts to check in outside the permitted window, When they tap the check-in button, Then the action is blocked and the UI displays the next allowed time or that the window has expired. - Given notifications are sent, When delivery callbacks are received, Then per-channel delivery status is recorded without duplicate log entries.
Geofenced Arrival Confirmation
- Given geofencing is enabled and the borrower granted location permission, When the device enters the pickup geofence during the pickup window, Then the booking updates to "Arrived (Geo-Confirmed)" and lat/long, accuracy, and timestamp are stored. - Given geofencing is disabled or permission is denied, When within the pickup window, Then manual check-in remains available and no location data is stored. - Given multiple geofence entry events occur, When processed, Then only the first arrival changes state; subsequent events are idempotently ignored and logged. - Given the borrower is outside the geofence radius, When an auto-arrival would trigger, Then no auto-confirmation occurs and the user is prompted to use manual check-in.
Lender QR Verification at Handoff
- Given a booking in "Arrived" or "Checked-In" state, When the lender scans the borrower’s valid booking QR (or vice versa), Then the handoff is verified, the booking transitions to "Checked-Out", and a verification record (scanner_id, code_id, timestamp) is saved. - Given an invalid, expired, or mismatched QR is scanned, When verification is attempted, Then the system rejects the scan with a clear error and no state change occurs. - Given intermittent network connectivity, When the scan event is retried, Then verification is processed at most once and duplicate submissions produce no duplicate state transitions.
Grace Period and No-Show Triggering the Relist Cascade
- Given a pickup window with a configured grace period, When window_end + grace elapses without verified arrival (geofence or QR) or required manual check-in, Then the booking is marked "No-Show" and the Relist Cascade is triggered to reassign the item to the next eligible borrower with compressed pickup windows. - Given a no-show policy with a deposit action is configured, When the no-show is recorded, Then the corresponding Stripe action (capture fee or release hold) is executed and the result is logged. - Given cascade is triggered, When the next borrower is selected, Then they are notified immediately and the calendar reflects new availability within the same operation. - Given downstream actions fail transiently, When retry policy runs, Then retries are attempted per configuration and final failure is logged and surfaced to operations without partial state corruption.
Auditability of Check-In, Arrival, Verification, and No-Show Events
- Given any check-in, geofence arrival, QR verification, no-show, override, or cascade event, When the event commits, Then an immutable audit record is saved with booking_id, actor (user/system), event_type, UTC timestamp, payload details, and previous->new state. - Given an authorized admin requests an audit trail for a booking, When queried, Then the complete ordered event log is returned and exportable as JSON. - Given a duplicate or out-of-order event submission occurs, When processed, Then the system preserves original records and appends idempotency markers without altering existing entries.
Manual Override With Reason Codes
- Given an active pickup, When the lender selects "Mark Arrived", "Mark No-Show", or "Extend Grace", Then a reason code selection is required (or "Other" with free text) and the action is blocked until provided. - Given an override is submitted, When processed, Then booking state transitions per action, notifications are sent to affected parties, audit record captures actor_id and reason, and any payment/cascade rules are applied. - Given an override violates temporal or policy constraints (e.g., marking arrived before window start), When attempted, Then the system prevents the change with a clear message and no state transition occurs.
Instant Relist with Compressed Windows
"As a lender, I want missed bookings to convert into shorter immediate pickup slots so that the next borrower can grab the item quickly without wasting my time."
Description

Automatically re-list the item with condensed pickup windows when the prior booking lapses, using heuristics to create shorter, near-term windows that fit lender preferences and neighborhood quiet hours. Avoid calendar conflicts by recalculating availability on the fly and batch adjacent pickups to reduce churn. Publish updated slots instantly and surface them to eligible backups and nearby borrowers. Throttle re-list frequency to prevent notification fatigue.

Acceptance Criteria
Auto-Relist Trigger on Lapse or Missed Check-In
Given an item has an active booking with a defined pickup window and check-in cutoff And the lender has enabled Instant Relist When the pickup window lapses without a borrower check-in Or the borrower fails to check in by the cutoff Then the system marks the booking as No-Show And relists the item within 5 seconds of the trigger And records the trigger reason and timestamp in the audit log
Generate Compressed Near-Term Windows Within Preferences and Quiet Hours
Given Instant Relist is triggered And lender availability windows and neighborhood quiet hours are configured When generating new pickup slots Then each slot duration is between configured MinCompressedDuration and MaxCompressedDuration And each slot duration is less than or equal to original_slot_duration × configured CompressionFactor And each slot start and end time fall within lender availability and outside quiet hours And all slots are scheduled within configured RepostHorizon from now
Conflict-Free Calendar Recalculation
Given existing bookings, holds, maintenance blocks, and lender blackout dates on the item calendar When publishing compressed slots Then no published slot overlaps with existing calendar blocks And any conflicting candidate slot is discarded before publication And concurrent relist triggers for the same item are serialized to prevent race conditions And the final published schedule is saved atomically
Batch Adjacent Pickups to Reduce Churn
Given multiple compressed slots are generated for backups in sequence And a configured BatchGapMinutes exists When scheduling the slots Then slots separated by less than or equal to BatchGapMinutes are merged into a single contiguous pickup session And remaining slots are arranged back-to-back with a gap less than or equal to BatchGapMinutes And the batched schedule is written to the item calendar
Instant Publication and Targeted Surfacing to Backups and Nearby Borrowers
Given compressed slots are created And a backup queue exists When publishing the relist Then the new slots appear on the item detail page and in search within 2 seconds of trigger And pre-approved backups receive notifications within 10 seconds And nearby eligible borrowers within configured RadiusMeters receive notifications within 10 seconds And ineligible or opted-out users receive no notifications
Relist Frequency and Notification Throttling
Given repeated relist triggers occur for the same item And global throttling settings are configured When evaluating whether to publish a relist and send notifications Then no more than MaxRelistsPerItemPerHour relists are published for that item And each user receives no more than MaxRelistNotificationsPerUserPerDay notifications about that item And multiple relists within a 15-minute window are coalesced into a single notification per user And throttled events are logged with suppression reasons
No Valid Compressed Window Fallback
Given Instant Relist is triggered And lender preferences and quiet hours eliminate all candidate slots within RepostHorizon When slot generation completes Then no relist is published And the prior booking remains closed as No-Show And an alert is sent to the lender suggesting preference adjustments And an audit event records the failure with candidate counts and constraints applied
Backup Borrower Pre-Approval and Auto-Reserve
"As a borrower, I want to join a pre-approved backup list so that I can secure last-minute openings without re-entering details."
Description

Enable borrowers to opt in as pre-approved backups by verifying identity, payment method, and deposit authorization ahead of time. When a cascade triggers, automatically hold the next slot for the highest-ranked backup and start a countdown to accept; on timeout or decline, progress to the next candidate without manual intervention. Show clear status to all affected borrowers and prevent double-booking or over-allocation.

Acceptance Criteria
Pre-Approval Opt-In and Verification Flow
- Given an authenticated borrower opts in as a backup When they submit identity, payment method, and deposit authorization Then the system verifies all three via integrated providers and sets borrower status to "Pre-Approved" on success within 10 seconds. - Given verification fails for any field When the borrower submits Then the system returns actionable error messages and does not set "Pre-Approved". - Given a borrower is pre-approved When their verification ages past policy thresholds Then the system flags "Reverification Required" and prevents auto-reserve until refreshed. - Then an audit record (user, method, providers, timestamps, outcome) is persisted.
Auto-Reserve on Cascade Trigger
- Given a cascade trigger due to missed pickup or no check-in When pre-approved backups exist Then create a hold for the highest-ranked eligible backup within 2 seconds of trigger. - Then set a countdown timer (configurable, default 15 minutes) and mark the item "On Hold" for that borrower. - Then send immediate in-app and push/email notifications to the held borrower; include expiration time and accept/decline actions. - Then block new public bookings for that time window during the hold.
Countdown Acceptance and Next-Up Progression
- Given a hold exists for a backup When the backup taps Accept before timer expiry Then confirm the reservation, place/refresh payment and deposit holds, and clear the countdown. - Given the backup taps Decline or timer expires When the hold is active Then cancel the hold, notify the borrower, and advance to the next eligible backup within 2 seconds. - Given the candidate list is exhausted When no one accepts Then re-list the item publicly and clear all holds. - Then ensure no overlapping holds remain and all state transitions are idempotent.
Status Visibility and Notifications
- Given an active cascade When statuses change (Hold, Accepted, Declined, Expired, Confirmed, Skipped) Then update borrower and lender UIs within 2 seconds and include timestamps. - Given non-active backups When another borrower is on hold Then show queue position and "Waiting" without exposing personal details of the active borrower. - Given the lender views the item When a cascade is in progress Then show current holder name, countdown, and next-up count. - Given any notification is sent Then it is logged with delivery status; failures are retried up to 3 times.
Double-Booking and Over-Allocation Prevention
- Given a borrower has an existing reservation overlapping the hold window When a cascade triggers Then skip that borrower and record reason "Overlap". - Given an item has inventory count of 1 When a hold is created Then prevent any other holds for the same time slice. - Given concurrent cascade events fire for the same item When processing assignments Then enforce a single assignment using idempotency keys and optimistic locking; no duplicate holds are created. - Given payment or deposit hold authorization fails on accept Then do not confirm the reservation and advance to the next candidate.
Ranking and Eligibility Determination
- Given multiple pre-approved backups exist When selecting next candidate Then compute a priority score from reliability rating, proximity, and time-in-queue with deterministic tie-breakers (earlier opt-in wins). - Given a borrower is blocked, unverified, has unpaid balance, or policy violations When evaluating eligibility Then exclude and record reason codes. - Given eligibility computation completes Then persist the ordered candidate list with scores and reasons for audit.
Audit Trail and Performance Metrics
- Given any cascade lifecycle event occurs Then write an immutable audit log with item ID, trigger reason, candidate list snapshot, selected candidate, actions, timestamps, outcomes. - Given production load When cascades execute Then 95th percentile time from trigger to first hold creation is <= 2 seconds; 95th percentile UI status propagation <= 2 seconds. - Given an admin requests metrics Then report acceptance rate, average steps to confirm, timeout rate, and mean time to reallocation, filterable by item and time range.
Eligibility and Fairness Rules
"As an organizer, I want the cascade to prioritize nearby and reliable borrowers so that pickups are smooth and equitable."
Description

Define ranking and eligibility policies for cascade reassignment, factoring in distance, reliability score, past no-shows, group/HOA access, and lender preferences (e.g., preferred neighbors, max borrow frequency). Enforce fairness safeguards like cool-downs and monthly caps to prevent hoarding, and provide transparent rationale to users for their position in the queue. Make rules configurable per item and per organization, with safe defaults and audit logs of every decision.

Acceptance Criteria
Eligibility Filter Enforcement Before Ranking
Given a cascade event for item X with multiple queued requests When the eligibility filter runs Then borrowers without required group/HOA access are excluded from the candidate set Given a borrower is currently within an active cool-down window When the eligibility filter runs Then the borrower is excluded and the next eligible date is computed and stored Given a borrower has reached the organization’s monthly borrow cap When the eligibility filter runs Then the borrower is excluded and shown the cap and reset date Given a lender has set a per-item max borrow frequency for item X When a borrower attempts to reserve within the restricted interval Then the borrower is excluded from the candidate set for item X Given the eligibility filter completes When the candidate list is finalized Then the system persists the candidate set with a unique decision ID and candidate count
Distance- and Reliability-Weighted Queue Ranking
Given a set of eligible candidates each with distance_km, reliability_score (0–100), and preference_flag (0 or 1) When ranking runs with default weights distance=0.5, reliability=0.4, preference=0.1 and max_radius_km=5 Then the system computes S = 0.5*(1 - min(distance_km,5)/5) + 0.4*(reliability_score/100) + 0.1*(preference_flag) for each candidate Given two or more candidates have equal S When tie-breaking is applied Then order by fewer past no-shows in the last 12 months, then by lower distance_km, then by earlier request timestamp Given identical inputs and rule version When ranking is executed multiple times Then the output order is deterministic and repeatable
Cool-Down Enforcement for No-Shows and Late Check-Ins
Given a borrower is marked as a no-show for any item in the organization When cool-downs are evaluated Then a 7-day organization-wide cool-down is applied by default and stored with start/end timestamps Given a borrower checks in more than 30 minutes after their pickup window start without lender approval When lateness is evaluated Then apply a 3-day cool-down by default and mark the event as late in the borrower’s reliability inputs Given organization or item-level overrides exist for cool-down durations When cool-downs are applied Then the item-level value overrides the organization default and the applied duration is shown in rationale
Monthly Caps and Per-Item Borrow Frequency Limits
Given an organization monthly cap default of 4 successful borrows per rolling 30 days When a borrower reaches the 4th successful borrow Then any additional requests within the window are ineligible and the next eligible date is displayed Given a lender sets a per-item max borrow frequency default of 1 borrow per 14 days per borrower When a borrower attempts to borrow the same item again within 14 days Then the request is marked ineligible for cascade reassignment Given custom cap and frequency values are configured When evaluations run Then item-level overrides take precedence over organization-level values and are enforced accordingly
Safe Defaults and Config Overrides (Org and Item)
Given a new organization without custom fairness rules When the Relist Cascade runs Then safe defaults are used: max_radius_km=5, no-show_cooldown_days=7, late_cooldown_days=3, monthly_cap=4, per_item_frequency_days=14, reliability_horizon_days=180, preference_boost_weight=0.1 Given administrators configure organization-level rules within allowed ranges (max_radius_km 0.5–20, monthly_cap 1–20, per_item_frequency_days 1–90, cooldown_days 1–30) When configurations are saved Then inputs are validated, versioned, and rejected with errors if out of range Given an item has explicit overrides When evaluating fairness rules for that item Then the item’s overrides supersede the organization defaults for that decision and the applied rule version is recorded
Transparent Queue Rationale to Users
Given a user views their position for item X When rationale is requested Then the UI displays the top three ranking factors with numeric values: distance_km, reliability_score, preference boost applied, along with current position and candidate count Given a user is ineligible for item X When rationale is requested Then the UI displays the exact rule(s) causing ineligibility (e.g., monthly cap reached, cool-down active, group access missing) and the next eligible date/time Given a decision ID exists for the current ranking When the user views rationale Then the displayed factors and values match the corresponding audit log entry for that decision ID
Comprehensive Audit Logging of Cascade Decisions
Given a cascade reassignment decision is made When the decision is finalized Then an immutable audit record is created containing: timestamp, decision_id, rule_version, evaluated configs, candidate inputs (anonymized IDs, distance_km, reliability_score, preference_flag), eligibility outcomes, final ranking, selected borrower, and rationale summary Given an admin or lender performs a manual override impacting eligibility or ranking When the override is saved Then the audit record includes actor identity, reason, fields changed, and pre/post values Given audit records are created When queried by authorized admins or item owners via API Then records are retrievable within 2 seconds of decision time and retained for at least 365 days
Payment and Deposit Hold Handoff
"As a lender, I want deposit holds to transfer automatically during reassignments so that I’m protected from no-shows without manual effort."
Description

Integrate with Stripe to seamlessly manage deposit authorizations across cascades: cancel or partially capture the original borrower’s hold per no-show policy, then re-authorize for the next borrower automatically. Ensure SCA flows are handled, retries are safe and idempotent, and edge cases like multi-currency and expired authorizations are covered. Emit clear receipts and notifications for each transition and reconcile events to the platform ledger for financial accuracy.

Acceptance Criteria
No-Show Deposit Policy Enforcement on Cascade
Given an original borrower’s pickup window lapses without a valid check-in When the Relist Cascade is triggered Then the system evaluates the no-show policy and either cancels the Stripe authorization or partially captures the no-show fee (rounded to the currency’s minor unit) not exceeding the authorized amount within 10 minutes And exactly one Stripe operation is executed (cancel or partial capture) for this borrower And a receipt is sent to the borrower and a notification to the lender within 2 minutes And a single immutable ledger entry is recorded with action, amount, currency, Stripe IDs, and timestamps And the item is marked available for the next borrower in the queue
Auto Re-Authorization for Next Borrower with SCA
Given a next eligible borrower is promoted by the Relist Cascade When a new deposit hold is created in Stripe Then the hold is authorized for the listing’s currency and policy-defined amount using an idempotency key scoped to (listing_id, borrower_id, cascade_step) And if SCA is required, the borrower is prompted and can complete the challenge within 10 minutes And upon SCA success, the authorization status is recorded and the borrower receives confirmation And if SCA fails or times out, the authorization is voided and the system advances to the next borrower automatically And no duplicate authorizations exist for the same cascade step
Idempotent Retries and Webhook Reconciliation
Given transient API errors or webhook delivery retries from Stripe When the same authorization/capture/cancel request is retried with the same idempotency key within 24 hours Then Stripe creates at most one corresponding object and the platform records at most one ledger entry And out-of-order or duplicate webhooks do not produce duplicate ledger entries And a reconciliation job runs every 15 minutes to match Stripe balance transactions and payment events to platform ledger entries for the past 24 hours And any mismatch is flagged to an error queue within 5 minutes with correlation IDs for investigation
Multi-Currency Deposit Handling
Given a listing defines its transaction currency (USD, EUR, or GBP) and borrowers may pay with cards in any currency When creating a deposit authorization Then the authorization is issued in the listing’s currency and respects Stripe currency minimums and increment rules (minor unit rounding) And policy-based amounts (flat or percentage) are computed precisely and rounded before authorization And receipts and ledger entries display the listing currency and amount; no on-platform FX conversion is performed And if the computed amount is below Stripe’s minimum for that currency, the borrower is blocked from checkout with an actionable error and the cascade proceeds to the next borrower
Expired Authorization Re-Auth or Cascade Skip
Given an existing deposit authorization is set to expire before the pickup window completes When the system detects an authorization will expire within 24 hours of pickup Then it attempts a single re-authorization using the stored payment method and prior consent, with a fresh idempotency key And if SCA is required, the borrower is prompted; success records the new authorization and preserves the booking And if re-authorization fails or SCA is not completed within 5 minutes, the borrower is removed from the slot, the old hold is released, and the cascade advances to the next borrower with notifications sent
Receipts, Notifications, and Ledger Integrity per Transition
Given any payment state transition related to a cascade (authorization, partial capture, cancel, release) When the transition is finalized Then a receipt is delivered to the affected borrower and a notification to the lender within 2 minutes including action, item, amounts, currency, policy reason, and Stripe IDs And a corresponding immutable ledger entry is created within 1 minute with a correlation ID linking the app event to the Stripe event IDs And the ledger entry status is updated to “reconciled” within 15 minutes upon receiving matching Stripe webhooks And audit logs allow retrieval of the full sequence of transitions for a booking within 2 seconds
Lender Controls and Notifications
"As a lender, I want configurable controls and actionable notifications so that I can manage exceptions without derailing the cascade."
Description

Provide lender-facing settings to enable/disable Relist Cascade, configure grace periods, define compressed window lengths, set allowable pickup hours, and choose notification channels. Deliver timely alerts to lenders and borrowers (push, email, SMS where permitted) with accept/decline actions and countdown timers. Allow lenders to pause a cascade, extend a window, or select a specific borrower, with all overrides logged for transparency and support.

Acceptance Criteria
Toggle Relist Cascade On/Off
Given a lender opens Lender Controls When the lender toggles Relist Cascade On Then the setting is saved server-side and persists across sessions And the UI reflects the On state immediately When the lender toggles Relist Cascade Off while a cascade is active Then a confirmation modal is shown with impact summary And upon confirm, the active cascade stops and the item returns to manual control within 3 seconds And a success toast confirms the change
Configure Grace Period and Compressed Window
Given a lender edits Relist Cascade settings When the lender sets a grace period between 0–30 minutes (integer) Then invalid inputs are blocked with inline error copy and no save occurs When the lender sets a compressed pickup window between 15–120 minutes in 5-minute increments Then the values save and are applied to the next re-list event And when a borrower fails to check in within the grace period Then the system re-lists the item using the configured compressed window length
Set Allowable Pickup Hours (with Time Zone)
Given a lender defines allowable pickup hours per day in their local time zone When Relist Cascade schedules a new pickup window Then the start and end times fall entirely within the defined hours And if the next available slot would be outside hours, it is shifted to the next allowable block on the same or next day And daylight saving changes are respected using the lender's time zone And blackout dates (if configured) are not scheduled
Select Notification Channels and Consent
Given a lender configures notification channels (push, email, SMS) for lender and borrower alerts When SMS is selected Then the system requires a verified phone number and explicit SMS consent before enabling And region-specific SMS restrictions are enforced When a notification is sent Then the system uses the selected channels with fallback order: push → email → SMS (if permitted) And recipients do not receive duplicate content within a 10-minute window And STOP/UNSUBSCRIBE replies disable future SMS for that user and log consent changes
Actionable Alerts with Countdown Timers
Given a borrower becomes next in queue via Relist Cascade When a notification is delivered Then it includes Accept and Decline actions and a live countdown matching the configured grace period And the countdown accuracy is ±1 second and halts on action or expiry When the borrower Accepts within the countdown Then payment/deposit hold is verified and the reservation is confirmed; borrower and lender receive confirmations When the borrower Declines or the countdown expires Then the system immediately advances to the next eligible borrower and sends new notifications And action links deep-link to the relevant screen; expired links display an informative state
Pause, Extend, or Choose Borrower with Audit Log
Given a lender views an active cascade When the lender selects Pause Then the cascade halts for a lender-specified duration (5 minutes–24 hours) and no auto-advances occur during pause When the lender selects Extend on the current borrower's window Then the window increases by a selectable amount (5–60 minutes) and countdowns update in real time When the lender chooses a specific borrower from the queue Then the selected borrower is promoted and notified; others are placed on hold And all overrides are audit-logged with timestamp, actor, action, reason (optional), and before/after state And logs are visible in the item's activity feed and exportable for support And concurrent actions are resolved deterministically: the first server-confirmed action applies; later conflicting actions receive a non-blocking update message

Priority Waitlist

Ranks waitlisted borrowers by reliability, proximity, and schedule fit, then fires instant offers with one-tap acceptance. Deposits are pre-authorized to speed handoffs. Lenders cut idle time; borrowers get fast second chances without refreshing listings.

Requirements

Reliability Score Engine
"As a borrower, I want my reliability to be recognized so that I get priority when I consistently follow through."
Description

Calculates a dynamic reliability score for each borrower using on-time pickups/returns, cancellation and no-show rates, lender ratings, verified identity status, dispute history, and time-decayed weighting. Stores scores securely and updates them after each transaction to reflect recent behavior. Provides cold-start defaults for new users and admin overrides for edge cases. Exposes an API and event hooks to the Priority Waitlist ranker, notifications service, and lender dashboards while respecting privacy and data minimization. Ensures explainability by returning top contributing factors for display in ranking explanations.

Acceptance Criteria
Dynamic Reliability Scoring with Time-Decay
Given a borrower has historical events with timestamps and ratings, When the reliability score is computed at time T, Then the score is a deterministic float in [0,100] with two decimal places for the same inputs and T. Given two borrowers with identical histories except one has events in the last 30 days and the other has events older than 180 days, When scores are computed, Then the borrower with more recent positive events has a higher score. Given events older than 180 days, When weighted, Then each such event contributes at most 0.5x the contribution of the same event occurring within the last 30 days. Given verified identity status is true, When the score is computed, Then a positive configurable boost is applied with default +3.00 points and capped at +5.00. Given increases in on-time pickups/returns or decreases in cancellation/no-show rates holding other factors constant, When compared to baseline, Then the score strictly increases; conversely, increases in cancellations, no-shows, or disputes strictly decrease the score. Given no input changes, When recomputed at the same timestamp T, Then the score remains unchanged.
Real-Time Post-Transaction Score Updates
Given a transaction for a borrower changes status to Completed On-Time, When the event is processed, Then the borrower’s score is recomputed and persisted within 5 seconds and last_updated is set to the processing timestamp. Given a transaction is marked Cancellation or No-Show, When processed, Then the score is recomputed and decreases relative to the immediately prior score if all else is unchanged. Given duplicate notifications for the same transaction_id and final status, When processed, Then the recomputation is idempotent and the resulting score is identical and only one audit record is written. Given a transient failure during recomputation, When the retry queue clears, Then the persisted score reflects the recomputation and no borrower score remains older than 10 minutes.
Cold-Start Defaults for New Borrowers
Given a new borrower with no historical events or ratings, When GET /scores/{borrower_id} is called, Then the response returns score=70.00, source=cold_start, and top_factors includes key=new_borrower_default. Given ADMIN_DEFAULT_SCORE is updated to 75.00, When a new borrower’s score is requested after configuration propagation, Then the returned score is 75.00 within 5 minutes. Given a borrower completes their first transaction, When the score is recomputed, Then source changes to computed and the score differs from the cold-start default by at least 0.10 points.
Admin Override with Expiration and Audit
Given an admin with role=RiskAdmin submits an override with score S in [0,100], reason text, and expires_at, When saved, Then GET /scores returns score=S, source=override within 5 seconds. Given an override request is missing reason or expires_at or expires_at > 90 days in the future, When validated, Then the request is rejected with HTTP 400 and no change is applied. Given an override reaches expires_at, When the next read occurs, Then the returned source is computed and score equals the computed value within 5 seconds of expiration. Given any override create/update/delete, When it occurs, Then an audit log entry is recorded with actor_id, borrower_id, previous_value, new_value, reason, and timestamp.
Explainability: Top Contributing Factors
Given GET /scores/{borrower_id} is called, When the response is returned, Then top_factors contains 3 to 5 items sorted by descending absolute contribution. Given each top factor, When inspecting, Then it includes fields key, human_readable_reason, sign in {+,-}, and contribution_pct in (0,100] and the sum of contribution_pct across items equals 100% ± 1%. Given identical inputs and timestamp, When called repeatedly, Then the same top_factors and ordering are returned. Given a factor key, When mapped, Then only privacy-safe keys are used (e.g., on_time_rate_90d, no_show_rate_180d, verified_identity, dispute_count_365d) and no raw PII is present.
Event Hooks for Downstream Ranker and Notifications
Given a borrower’s score changes, When the change is persisted, Then an event score.updated is published within 2 seconds containing borrower_id, score, source, version, top_factor_keys, and occurred_at. Given an emitted event, When inspecting the payload, Then it contains no PII (no name, email, phone, address). Given a duplicate publish attempt, When consumers receive an event with the same idempotency_key, Then it is treated as a duplicate and ignored. Given a delivery failure to a subscriber, When retries are scheduled, Then deliveries are retried with exponential backoff for at least 24 hours. Given multiple score changes occur rapidly, When events are consumed out of order, Then consumers can use monotonically increasing version to discard stale events.
Privacy, Data Minimization, and Secure Storage
Given the score store is configured, When data is at rest, Then it is encrypted with AES-256 and keys managed by the platform KMS; and when in transit, TLS 1.2+ is enforced. Given service-to-service access, When a token with scope waitlist_ranker.read is used, Then only fields borrower_id, score, source, top_factors, last_updated, version are returned; PII and raw transaction history are not returned. Given a dashboard request with scope lender_dashboard.read, When authorized, Then only the same minimal fields are returned; no PII is leaked. Given any API access, When processed, Then an audit log entry is created with caller_service, scope, purpose, and timestamp. Given factor aggregation windows, When computation runs, Then aggregates older than 365 days are excluded from both storage and computation.
Proximity Ranker
"As a borrower, I want nearby items prioritized so that pickups are convenient and fast."
Description

Computes a proximity score based on travel time and distance between the lender’s pickup location and borrower’s preferred pickup address, supporting multiple saved addresses and HOA/building geofences. Integrates with mapping APIs for ETA calculations, caches results to control costs, and degrades gracefully when location permissions are limited. Handles consent, privacy, and rounding rules when displaying distances. Publishes the proximity score to the Priority Waitlist ranker and exposes configuration for lender-defined pickup radius.

Acceptance Criteria
ETA-Based Proximity Score Calculation
Given a valid lender pickup point and a borrower preferred pickup address with mapping API access When proximity is computed Then the system requests ETA and road distance using driving mode with live traffic where available And the proximity score is normalized to a 0–100 scale where lower ETA/distance yield higher scores And for two borrowers where ETA1 < ETA2 and Distance1 <= Distance2, Score1 > Score2 by at least 1 point And scores are deterministic for identical inputs within the same 5-minute window
Multiple Saved Addresses Selection
Given a borrower with multiple saved addresses and one marked as preferred for this request When proximity is computed Then only the selected preferred address is used as the destination And the response includes used_address_id matching the preferred address And if no address is selected, the primary saved address is used by default And changing the preferred address triggers recomputation and updates the score within 5 seconds
HOA/Building Geofence Origin Handling
Given a building/HOA geofence with a configured pickup point and a borrower address inside that geofence When proximity is computed Then the destination is set to the geofence pickup point, not the unit’s exact coordinates And the response includes geofence_id and used_address_id And ETA/distance calculations consistently use the geofence pickup point across repeated requests
Mapping API Result Caching
Given identical origin, destination, transport mode, and time-bucket inputs within the configured TTL When proximity is recomputed Then the result is served from cache (cache_hit=true) and no external mapping API call is made And after TTL expiry the next request refreshes the cache (cache_hit=false, cache_refreshed=true) And cache keys normalize coordinates to 5 decimal places to prevent precision misses And under a test workload with ≥50% repeated origin-destination pairs, cache hit rate is ≥60%
Graceful Degradation With Limited Location Permissions
Given mapping ETA is unavailable or precise location permission is denied and no saved address is available When proximity is computed Then the system falls back in order: device coarse location (geohash precision 5) -> profile ZIP/postcode centroid -> city centroid And the score is derived from great-circle distance only and marked confidence="low" And the API returns reason="fallback" with the chosen fallback tier And no precise coordinates are stored or displayed in this mode
Privacy, Consent, and Rounded Distance Display
Given location use requires consent When saved addresses or device location are used for proximity Then explicit consent for the source exists and is recorded (consent_source, consent_version, timestamp) And distances exposed via API/UI are rounded to the nearest 0.1 mi in US locales or 0.1 km otherwise, with a minimum floor display of 0.1 unit And logs and analytics redact coordinates beyond 2 decimal places and exclude full street addresses
Publish Score and Enforce Pickup Radius
Given a lender-configured pickup radius When proximity is computed Then borrowers with distance beyond the radius are labeled out_of_radius and no score is published to the Priority Waitlist ranker And for in-radius borrowers the service publishes {borrower_id, lender_id, used_address_id, geofence_id, eta_minutes, distance_km, score, confidence, computed_at} to the ranker And changes to the pickup radius trigger recomputation and republishing within 60 seconds
Schedule Fit Scoring
"As a borrower, I want offers that fit my schedule so that I can accept without back-and-forth."
Description

Generates a schedule fit score by intersecting the lender’s live calendar availability with each waitlisted borrower’s availability windows, accounting for time zones, daylight saving changes, required buffers, and existing overlapping reservations. Proposes the earliest feasible pickup/return slots and adjusts automatically when conflicts arise. Integrates tightly with Sharehood’s booking calendar and the Instant Offer Dispatch to attach proposed times to offers. Provides APIs to recalculate scores when availability changes.

Acceptance Criteria
Cross-Time-Zone and DST-Safe Intersection
Given a lender timezone set to America/Los_Angeles and a borrower timezone set to America/Denver And the lender availability spans a DST transition window And the borrower availability overlaps the lender window for at least the loan duration And required buffers of 15 minutes apply before pickup and after return When the system computes schedule fit and proposed pickup/return slots Then the proposed slot start and end are returned as ISO 8601 timestamps with offsets for both parties and as UTC instants And the lender-local and borrower-local representations convert to the same UTC instants And no proposed local time falls into an ambiguous or nonexistent local-time interval And the schedule fit score is greater than 0
Earliest Proposal With Overlap And Buffers
Given lender availability on 2025-08-26 09:00–12:00 America/New_York And an existing lender reservation 09:30–10:00 with a global 10-minute buffer before and after all bookings And borrower availability 08:00–11:00 America/New_York And requested loan duration 30 minutes When the system computes schedule fit Then the earliest proposed pickup is 10:10 and return is 10:40 in America/New_York And the proposal respects all buffers and does not overlap existing reservations And the schedule fit score is positive and attached to the borrower
Automatic Recalculation On New Conflict
Given an offer has a proposed slot attached from schedule fit And a new overlapping reservation is created on the lender’s calendar before the offer is accepted When the conflict is saved Then the system recalculates the schedule fit within 3 seconds And the offer is updated with the next earliest feasible slot if available And if no feasible slot exists, the offer is automatically canceled with reason "CONFLICT_NO_SLOT"
Recalculate API Contract And Performance
Given a request to POST /api/v1/schedule-fit/recalculate with a lenderId and a list of borrowerIds (up to 100) When the request is valid Then the API responds 200 with a list containing each borrowerId, scheduleFit.score (0–100), and proposedSlots[0].pickupAt/returnAt And p95 latency is <= 150 ms per borrower for batches up to 100 And scores are deterministic for identical inputs across repeated calls
No Intersection Returns Zero Score And No Proposal
Given lender and borrower availabilities that do not intersect when buffers and existing reservations are applied When schedule fit is computed Then scheduleFit.score equals 0 And proposedSlots is an empty array And no Instant Offer is dispatched for that borrower
Attach Proposed Times To Instant Offer
Given a borrower is ranked high enough to receive an Instant Offer And schedule fit has computed a proposed slot When the Instant Offer is dispatched Then the offer payload includes pickupAt and returnAt equal to the top proposed slot in UTC and in the lender’s local timezone fields And upon one-tap acceptance, a booking is created with those times if still valid And if the slot becomes invalid before acceptance, the acceptance fails with reason "SLOT_INVALIDATED" and no booking is created
Instant Offer Dispatch
"As a waitlisted borrower, I want instant offers with one tap so that I can secure the item quickly."
Description

Sends real-time, ranked offers to top waitlisted borrowers with one-tap acceptance via deep links, using push notifications with SMS/email fallback. Reserves the item for a configurable time-to-live (TTL) to prevent double-booking, and automatically advances to the next candidate on expiration or decline. Ensures concurrency controls, idempotency, and rate limiting across channels. Localizes content, supports accessibility standards, and logs events for auditing and analytics. Integrates with Schedule Fit Scoring to include proposed pickup windows and with Deposit Pre-Authorization to validate payment before offer delivery.

Acceptance Criteria
Ranked Offer Construction with Schedule Fit Windows
Given an item transitions to Available and has a non-empty waitlist When the system constructs offers Then candidates are ranked using the configured weights for reliability, proximity, and schedule fit and the top N (configurable) are placed in the offer queue And the offer payload includes: item name, lender alias, proposed pickup window(s) from Schedule Fit Scoring in the candidate’s timezone, deposit amount/currency, expiration timestamp (TTL), and a one-tap deep link And candidates outside the lender’s radius or with conflicting holds are excluded from the queue And ranking is deterministic given identical inputs and includes a documented tie-break rule (earlier waitlist join time wins) And the end-to-end latency from availability signal to first offer queued is ≤ 1 second under normal load
Deposit Pre-Authorization Gate
Given a candidate is about to receive an offer When the system validates payment Then a Stripe deposit pre-authorization for the configured hold amount succeeds before any notification is sent And on pre-authorization failure, no offer notification is sent to that candidate, the failure reason is logged, and the system advances to the next candidate within 500 ms And on decline or TTL expiration, the pre-authorization is promptly released within 2 minutes And idempotency keys ensure duplicate pre-authorization attempts for the same offer/candidate do not create multiple holds
Multi-Channel Dispatch with Fallback and Rate Limiting
Given a candidate has multiple reachable channels (push, SMS, email) When the system dispatches an offer Then push is attempted first with an acknowledgment window of 10 seconds And if push is not acknowledged or the device is unreachable, SMS is sent; if SMS fails, email is sent And per-user rate limits are enforced: ≤ 3 SMS/day and ≤ 5 emails/hour, with one active notification per item/candidate at a time And all channels use a shared idempotency key so the candidate receives at most one actionable offer message per offer And each message includes localized summary, TTL, and the one-tap deep link And dispatch latency per channel attempt is ≤ 500 ms under normal load
TTL Reservation, Auto-Advance, and Concurrency Controls
Given an offer is sent When the TTL countdown starts (configurable, default 15 minutes) Then the item is reserved in state OfferHeld for that candidate and is blocked from other bookings And if the candidate accepts within TTL, the reservation converts to a booking atomically and the queue is cleared And if the candidate declines or TTL expires, the system releases the hold and advances to the next queued candidate within 2 seconds And in concurrent accepts, the first committed transaction wins; subsequent accepts receive an explicit "Offer no longer available" response And all state transitions are idempotent and retriable without creating duplicate bookings
One-Tap Acceptance via Deep Link with Idempotent Processing
Given a candidate receives an offer notification When they tap the deep link Then the app opens to an acceptance screen (or a mobile web fallback if the app is not installed) within 2 seconds And the screen shows item details, deposit summary, and proposed pickup window(s) for one-tap confirm And on confirm, the server creates the booking or returns a clear error if the offer has expired or been taken And repeated taps or retries are handled idempotently, yielding a single booking and consistent confirmation status And the deep link token is signed, user-bound, and expires at TTL; attempts after expiry are rejected with a localized message
Localization and Accessibility Compliance
Given a candidate’s locale and accessibility settings When the offer content and notifications are generated Then all strings are localized for supported locales with English fallback, dates/times are formatted in the candidate’s timezone, and RTL languages render correctly And interactive elements meet accessibility standards: screen-reader labels for action buttons and links, focus order is logical, and color contrast ≥ 4.5:1 And dynamic type is supported without truncating critical information on acceptance screens and notifications
Auditing and Analytics Event Logging
Given offer lifecycle events occur When the system processes create, dispatch, deliver, accept, decline, and expire actions Then it emits audit events (OfferCreated, OfferPreAuthSucceeded/Failed, OfferDispatched, OfferDelivered{channel}, OfferAccepted, OfferDeclined, OfferExpired) with fields: offerId, itemId, lenderId, candidateId, channel, timestamps, TTL, locale, idempotencyKey, and outcome And delivery outcomes per channel (delivered/failed) are captured within 30 seconds of attempt And events are exactly-once per state transition (idempotent), redact PII beyond IDs, and are retained for ≥ 365 days for audit queries
Deposit Pre-Authorization
"As a lender, I want deposits pre-authorized before offers go out so that no-shows are reduced."
Description

Pre-authorizes the required deposit via Stripe at offer time to reduce no-shows and speed handoffs. Performs card validation and 3DS challenges when required, retries on transient failures, and clearly communicates hold amounts and release timing. Releases holds on decline or expiry and maintains holds until pickup completion when accepted, following Sharehood’s deposit policy. Provides webhooks and idempotent operations, records receipts, and updates UI states across lender and borrower views. Ensures compliance with PCI and local regulations.

Acceptance Criteria
Offer-Time Deposit Pre-Authorization & Messaging
Given a borrower is eligible and an instant offer is generated When the offer is dispatched Then the system creates a Stripe pre-authorization for the configured deposit amount in the listing currency and receives an authorized status within p95 2.5s and p99 5s And the offer notification and in-app banner display the exact hold amount, currency, and policy-based release timing using locale-aware formatting And the hold identifier, amount, currency, and expiration timestamp are persisted atomically with the offer record
Strong Customer Authentication (3DS) Flow
Given the pre-authorization requires SCA/3DS per Stripe response When the borrower opens the offer prompt Then a 3DS challenge is presented inline and can be completed without navigation And if the challenge succeeds within 10 minutes, the hold status updates to authorized and the offer remains active And if the challenge fails or times out, the pre-authorization is canceled and the offer auto-expires with an actionable message to update payment method And all 3DS outcomes are recorded with associated Stripe intent IDs
Reliability: Retry Strategy and Idempotency
Given the pre-authorization attempt fails due to a transient condition (network timeout, 5xx, rate_limit) When the system retries Then up to 3 retries occur within 90 seconds using exponential backoff and a stable idempotency key per offer And Given a permanent decline code (card_declined, do_not_honor, insufficient_funds) Then no retries are attempted, the offer is not delivered or is withdrawn, and the borrower is prompted to update payment method And repeated triggers (duplicate events or replays) return the same Stripe intent and do not create multiple holds
Hold Lifecycle Management Until Pickup Completion
Given an offer is accepted and a hold exists When acceptance is recorded Then the hold remains authorized until pickup completion or hold expiry, whichever comes first, per deposit policy And if the hold is within 24 hours of expiring before pickup, the system attempts re-authorization on the same card and notifies the borrower; on failure, the booking is paused and the borrower has 2 hours to resolve And upon pickup completion, the hold transitions according to policy (release_on_pickup or retain_until_return), and the state change is persisted and auditable
Hold Release on Offer Decline or Expiry
Given a pre-authorization hold exists for an offer When the borrower declines the offer or the offer expires without acceptance Then the Stripe authorization is canceled within 60 seconds and the hold is released And lender and borrower UIs reflect "Hold released" within 5 seconds and show $0 outstanding And a release event with timestamps and Stripe IDs is stored for audit
Webhooks and Audit/Receipts
Given any hold state change (authorized, requires_action, failed, released, reauthorized) When the event occurs Then a signed webhook (per endpoint secret) is emitted within 3 seconds and retried with exponential backoff for up to 24 hours until a 2xx response is received And a receipt entry is created containing masked card brand/last4, amount, currency, deposit policy reference, and Stripe IDs, visible in both borrower and lender histories and exportable as PDF And no PAN/CVV is stored; payment metadata adheres to data retention policy with redaction applied within 30 days where applicable
PCI and Local Regulatory Compliance
Given payment operations are executed Then Sharehood systems never handle raw card data; only Stripe tokens/IDs are processed and stored (SAQ A scope) And SCA enforcement is active for applicable regions (EEA/UK) and verified in staging and production via test cards and monitoring And regional rules on deposit holds, disclosures, and refund timelines are documented and validated for the top 5 operating locales; receipts include required legal text And quarterly PCI SAQ A is completed with evidence; API keys are segregated by environment; access to payment data is least-privileged and logged
Lender Priority Controls
"As a lender, I want control over how the waitlist is prioritized so that it reflects my preferences."
Description

Offers a lender-facing dashboard to configure waitlist behavior, including weighting sliders for reliability, proximity, and schedule fit; maximum waitlist size; offer TTL; blackout times; and an auto-advance toggle. Displays the current ranked queue with transparent explanations of ranking factors and allows safe manual reordering with audit trails. Persists settings per item and per lender profile with sensible defaults. Integrates with the ranking engine and notification system to apply changes in real time.

Acceptance Criteria
Configure ranking weight sliders for reliability, proximity, and schedule fit
Given a lender opens the Priority Controls for an item or the lender profile When the lender adjusts weight sliders for Reliability, Proximity, and Schedule Fit within 0–100 Then the UI displays a live total that must equal 100 before Save is enabled And default weights are Reliability=50, Proximity=30, Schedule Fit=20 for new profiles/items And slider inputs reject values outside 0–100 and step in whole integers And unsaved changes trigger a confirmation prompt if navigating away And on Save, the stored weights equal the on-screen values
Persist settings per lender profile and per item with sensible defaults and inheritance
Given a lender has profile-level default settings saved When the lender creates a new item Then the item inherits the profile defaults for all controls When the lender overrides any control at the item level and saves Then the item uses the overridden value and the profile default remains unchanged And a Reset to Profile Defaults action restores inherited values for the item And settings persist across sessions and devices for the same account And if an item has no override for a control, the profile default is applied at runtime
Apply control changes in real time to the ranking engine and notifications
Given an item has an existing waitlist and the lender saves updated controls When the save completes Then the ranking engine re-ranks the item’s queue within 2 seconds And lender and borrower UIs displaying the queue reflect the new order within 3 seconds or next poll And existing active offers are not revoked; changes affect subsequent offers only And exactly one re-rank event is emitted per save to avoid duplicate notifications
Enforce maximum waitlist size with clear UX and overflow handling
Given a lender sets the Maximum Waitlist Size between 1 and 1000 (default 50) and saves When the waitlist size reaches the cap Then new join attempts are blocked with a message explaining the list is full And the lender can increase the cap and new joins are allowed immediately thereafter When the lender lowers the cap below current size Then no existing entries are removed, and new joins remain blocked until size ≤ cap
Configure offer TTL and auto-advance behavior
Given a lender sets Offer TTL between 5 and 1440 minutes (default 30) and toggles Auto-Advance on When an active offer expires or is explicitly declined Then the next eligible candidate receives an offer within 10 seconds And if Auto-Advance is off, no new offer is sent until the lender triggers Send Next Offer And accepted offers do not trigger further auto-advance for the same slot And each offer record stores its TTL, start time, and outcome timestamp
Define and enforce blackout times for offers and pickups
Given a lender configures blackout times (one-time or recurring) in the lender’s time zone and saves When the system would send an offer whose proposed pickup window overlaps a blackout Then the system does not send the offer and schedules the next permissible window or queues the send until blackout ends (per configuration) And outstanding offers whose TTL ends during a blackout do not send auto-advance offers until blackout ends And the UI validates and prevents overlapping or invalid blackout entries
Ranked queue display with factor explanations and safe manual reordering with audit trail
Given a lender views the ranked queue for an item Then each borrower entry shows position, total score (0–100), factor breakdown (Reliability/Proximity/Schedule Fit), and eligibility flags And ties are broken deterministically by higher Reliability score, then closer Proximity, then better Schedule Fit, then earlier waitlist join time When the lender drags to reorder eligible entries and saves Then the new order is applied immediately and persists until the lender clears overrides And ineligible borrowers cannot be moved above eligibility constraints And an audit log entry is created recording before/after positions, actor ID, timestamp, and a required reason And an Undo option is available for the last change for 5 minutes And other viewers of the queue see the update within 3 seconds
Fairness and Anti-Gaming Safeguards
"As a borrower, I want a fair waitlist so that I'm not consistently deprioritized by gaming or edge cases."
Description

Implements protections to keep the queue fair and trustworthy, including cooldowns after declines, penalties for repeated no-shows, tie-break rules, rotation to prevent the same users from always losing by milliseconds, and detection of location spoofing or identity abuse. Provides clear user messaging about rules and consequences, exposes an appeal/support flow, and maintains audit logs for moderation. Integrates with Reliability Score Engine to adjust scores based on policy violations.

Acceptance Criteria
Cooldown After Offer Decline
Given a borrower on a waitlist receives an instant offer for an item When the borrower taps Decline Then a 12-hour cooldown is applied to that borrower for the same item and equivalent listings And the borrower is skipped from receiving instant offers for that item during the cooldown And the borrower sees a visible cooldown banner with a countdown timer on the item page Given a borrower has declined 3 instant offers for the same item within a 7-day period When the third decline is recorded Then the cooldown extends to 48 hours And an in-app message explains the rule and next eligible time Given a borrower’s cooldown has expired When the system generates the next instant offer for that item Then the borrower becomes eligible again with no additional penalty And an audit log entry is recorded for cooldown start and end with timestamps
No-Show Penalty and Appeal Flow
Given a lender marks a reservation as No-Show within 24 hours of the scheduled pickup window When the platform confirms the no-show via counterparty acknowledgment or automated pickup/non-scan signals Then the borrower’s Reliability Score is reduced by 20 points And the borrower is deprioritized on the waitlist for the affected item category for 14 days And the borrower receives an in-app and email notification with reason, impact, and an Appeal button Given a borrower submits an appeal within 48 hours of notification with evidence When a moderator approves the appeal Then the score change and deprioritization are fully reversed And the borrower is notified of the reversal And the audit log records the original action and the reversal with moderator ID and reason codes Given multiple reports are filed for the same reservation When penalties are applied Then the system ensures penalties are applied only once per reservation ID
Deterministic Tie-Break and Rotation
Given two or more waitlisted borrowers have identical priority scores for the same pickup window When the system must select a recipient for an instant offer Then the selection is made using a round-robin rotation token maintained per item And the token advances after each tie-break so the next borrower wins the next tie in that item And an audit entry stores the tie-break inputs and winner ID Given multiple one-tap acceptances arrive within the acceptance window with timestamp deltas ≤ 100 ms When the system determines the winner Then the same rotation token is used to break the tie And non-winners retain their queue position without penalty Given a borrower participates in repeated tie-breaks for the same item within 30 days When outcomes are tallied Then no borrower loses more than 2 consecutive tie-breaks; the next tie auto-assigns to them
Location Spoofing Detection and Enforcement
Given a borrower attempts to accept an instant offer When the system detects a location anomaly (GPS vs network/home geofence mismatch > 2 km or implied travel speed > 120 km/h within 10 minutes) Then the acceptance is paused and the borrower is prompted to re-verify location via OS-level prompt or SMS pin to registered phone And the instant offer is held for up to 2 minutes pending verification before moving to the next candidate Given the borrower successfully completes verification within the hold window When the verification result is received Then the acceptance proceeds without penalty And the audit log records the verification event Given the borrower fails or dismisses verification or repeats anomalies 3 times in 30 days When enforcement triggers Then the borrower’s Reliability Score is reduced by 30 points and instant offers are suspended for 7 days And the borrower is notified with steps to remediate
Identity Linking and Abuse Prevention
Given multiple accounts share two or more strong signals (device fingerprint, payment instrument, phone number, or government ID) When the system evaluates an instant offer eligibility Then the accounts are linked for risk review and one-tap offers are temporarily disabled for the linked cluster And affected users are prompted to complete KYC re-verification Given KYC re-verification succeeds and no policy violations are found When eligibility is recalculated Then one-tap offers are re-enabled and no score penalty is applied Given confirmed identity abuse (ban evasion, duplicate borrower accounts to gain priority) When a moderator finalizes the decision Then secondary accounts are deactivated, the primary account receives a 50-point Reliability Score reduction, and a 30-day instant-offer suspension is applied And all actions are logged with decision IDs and evidence references
Reliability Score Engine Integration
Given a policy event occurs (decline cooldown, no-show, spoofing, identity abuse) When the event is recorded Then the Reliability Score Engine receives an idempotent update within 5 seconds (p99) with event type, weight, and reason code And the borrower’s new score is reflected in waitlist ranking within the next scheduling cycle (< 10 seconds p99) Given duplicate or retried event messages are received When the engine processes the message Then the score is updated exactly once and the operation is logged as a deduplicated event Given a score change occurs When an admin queries the score history Then the engine returns a chronological ledger of changes with event IDs that match audit logs
Audit Logging and Moderation Traceability
Given any fairness-related action occurs (cooldown start/end, penalty applied/reversed, tie-break decision, verification prompt, identity link) When the action is committed Then an append-only audit entry is created with timestamp, actor/service, user IDs, item ID, decision ID, reason code, old/new scores, and request correlation ID And entries are immutable and retained for 18 months Given a moderator opens the audit console When filters are applied by user ID, item ID, action type, or date range Then results return within 2 seconds for up to 10,000 entries and can be exported as CSV with PII fields redacted Given a data subject access request (DSAR) is executed When an export is generated Then audit entries exclude sensitive token values and display only permitted metadata per privacy policy

Hold Surge

Applies a temporary, transparent boost to deposit holds for high-risk scenarios—repeat no-shows, peak-time pickups, or first-time borrowers—then tapers back after on-time handoffs. Deters flakes without punishing reliable neighbors and clearly shows the steps to reduce holds.

Requirements

Risk Trigger Engine
"As a platform product owner, I want a configurable risk engine that scores each booking so that deposit holds scale appropriately with risk without penalizing reliable neighbors."
Description

Implements a configurable rules-and-scoring service that evaluates each booking for no‑show risk using signals such as repeat no‑show history, account age/first‑time borrower status, verified identity/payment status, item demand, organizer-defined peak windows, and pickup overlap density. The engine outputs a risk tier and hold multiplier, along with human-readable reasons to power transparent messaging. Weights, thresholds, and inclusion of specific signals are versioned and tunable per organization (HOA/tenant group) with safe defaults at the platform level. The service is stateless at runtime (reads from risk profile and event history) and exposes an idempotent API consumed by checkout, calendar, and payments. Decisions are logged with feature flags to support A/B experiments, fairness checks, and rapid rollback.

Acceptance Criteria
First-Time Borrower in Peak Window with High-Demand Item
Given platform config v1.0 with risk thresholds Low<40, Medium 40-69, High>=70 and multiplier mapping Low=1.0, Medium=1.3, High=2.0 And borrower account_age_days=2, no prior bookings, payment_verified=false, identity_verified=false And item_demand_percentile=90 And current_time is within the organizer-defined peak window And overlap_density=2 concurrent pickups at pickup time When the Risk Trigger Engine evaluates booking_id="BK-001" for org_id="ORG-123" Then response.risk_tier="High" and response.hold_multiplier=2.0 And response.reasons (codes) include ["first_time_borrower","peak_window","high_demand_item","overlap_density","payment_unverified","identity_unverified"] And response.reasons_human is a non-empty array mapped 1:1 to reasons codes And response includes config_version="v1.0", organization_id="ORG-123", decision_id, and timestamp (ISO-8601) And HTTP status=200
Repeat No-Show Borrower Off-Peak with Verified Profile
Given platform config v1.0 with risk thresholds Low<40, Medium 40-69, High>=70 and multiplier mapping Low=1.0, Medium=1.3, High=2.0 And borrower has no_shows_last_60d=2 And borrower payment_verified=true and identity_verified=true And item_demand_percentile=30 And current_time is outside any organizer-defined peak window When the Risk Trigger Engine evaluates the booking Then response.risk_tier="Medium" and response.hold_multiplier=1.3 And response.reasons include ["repeat_no_show"] and do not include ["peak_window","high_demand_item"] And HTTP status=200
Org-Specific Weights and Thresholds with Versioned Config
Given org_id="ORG-A" uses config version v2.3 with High threshold=60 and multiplier mapping Low=1.0, Medium=1.4, High=1.9 And org_id="ORG-B" uses platform default config v1.0 with High threshold=70 and multiplier mapping Low=1.0, Medium=1.3, High=2.0 And the same booking context is evaluated for both ORG-A and ORG-B When the Risk Trigger Engine evaluates for ORG-A and ORG-B Then ORG-A response.risk_tier="High" and response.hold_multiplier=1.9 And ORG-B response.risk_tier="Medium" and response.hold_multiplier=1.3 And each response includes its own config_version and organization_id And each decision is logged with decision_id, organization_id, config_version, and an immutable config_hash
Idempotent and Stateless Decision API Across Instances
Given request payload with booking_id="BK-123" and idempotency_key="IDEMP-123" And two different stateless service instances receive the same request within 5 minutes When the Risk Trigger Engine processes the request on both instances and on retries Then all successful responses have identical risk_tier, hold_multiplier, reasons, config_version, organization_id, and decision_id (trace_id may differ) And only one decision log entry exists per idempotency_key And no in-memory/session state is required to reproduce the decision
Graceful Degradation When External Signals Are Unavailable
Given the payments service returns 503 and the identity service exceeds a 200 ms timeout And fallback defaults are configured for missing signals When the Risk Trigger Engine evaluates a booking during this outage Then user-facing response.reasons do not contain outage details And decision_log.missing_signals includes ["payments_status","identity_status"] And response.risk_tier does not exceed "Medium" due solely to missing signals And response.hold_multiplier remains within configured bounds for Medium tier And P95 response time remains <= 300 ms
Decision Logging for A/B Experiments and Fairness Audits
Given feature flag "hold_surge_v3" is active with variants ["control","treatment"] And borrower belongs to variant "treatment" When the Risk Trigger Engine evaluates the booking Then a decision log record is written containing booking_id, organization_id, experiment_name, variant, inputs_snapshot (non-PII keys and normalized values), risk_tier, hold_multiplier, reasons, config_version, decision_id, and timestamp And 99.9% of decision logs are successfully delivered to the analytics pipeline within 60 seconds And on transient log delivery failure, the engine still returns HTTP 200 and enqueues a retry with exponential backoff
Performance and Scalability Under Load
Given mixed booking traffic at 500 requests per second sustained for 15 minutes with 3 active org configs When the Risk Trigger Engine handles requests Then P95 latency <= 120 ms and P99 latency <= 250 ms And error rate (5xx) < 0.5% And CPU and memory utilization remain below 70% of allocated resources And no more than 0.1% requests exceed a 1 s timeout
Dynamic Deposit Calculator
"As a borrower, I want to see exactly how my deposit hold is calculated so that I understand the amount and can decide whether to proceed."
Description

Calculates the final deposit hold amount by applying the risk multiplier to the item’s base deposit, enforcing min/max caps per category, organizer-specific ceilings, and currency rounding rules. Supports multi-item bookings, splitting holds per item when needed, and consolidating when allowed by the processor. Provides a preview in checkout with baseline vs. boosted comparison and itemized reasons. Exposes synchronous results for UI display and asynchronous recalculation on booking changes (time edits, item swaps). Emits telemetry on computed exposure to monitor platform risk and conversion impact.

Acceptance Criteria
Risk Multiplier with Category Caps
Given an item with baseDeposit B, riskMultiplier M, and category caps min Cmin and max Cmax When the calculator computes the per-item hold before organizer ceilings Then the per-item hold H = min(max(B*M, Cmin), Cmax) And H is rounded according to currency rules only after this step is complete
Organizer Ceiling Overrides Total Hold
Given a booking with N items, each with computed per-item hold Hi (after category caps), and an organizerCeiling T When the processor allows a consolidated authorization Then totalHold = min(sum(Hi), T) And the preview flags organizerCeilingApplied = true when sum(Hi) > T When the processor requires split authorizations Then per-item holds are proportionally scaled to Hi' such that sum(Hi') = min(sum(Hi), T) before currency rounding And after currency rounding, |sum(Hi') - min(sum(Hi), T)| < 1 minorUnit And the itemized holds Hi' are returned per item
Currency Rounding per Locale
Given a target currency with ISO 4217 minorUnit exponent E When the calculator outputs any hold amount Then the amount is rounded to E decimal places using half-up rounding And for zero-decimal currencies (E=0), amounts are whole integers And for currencies with E=3, three-decimal rounding is applied And rounding occurs after applying multipliers, category caps, organizer ceilings, and any proportional scaling
Multi-Item Booking: Split vs. Consolidated Holds
Given a booking with multiple items and a payment processor capability flag consolidateHolds When consolidateHolds = true and all items share the same currency and merchant account Then the calculator returns a single authorization amount equal to the rounded totalHold and an itemizedHoldBreakdown for preview When consolidateHolds = false or items span different currencies or merchant accounts Then the calculator returns separate authorization amounts per item consistent with itemizedHoldBreakdown
Checkout Preview: Baseline vs. Boosted with Reasons
Given checkout initiation with selected items and borrower risk inputs When the calculator returns synchronous results Then the preview payload includes per item: baseDeposit, appliedMultiplier, boostedDepositBeforeCeil, categoryMin, categoryMax, cappedDeposit, reasonCodes[] And the preview includes overall: totalBaseline, totalBoostedBeforeCeil, totalAfterCeil, consolidationMode (split|consolidated), organizerCeilingApplied (boolean) And reasonCodes enumerate all risk factors contributing to the multiplier (e.g., FIRST_TIME_BORROWER, REPEAT_NO_SHOW, PEAK_TIME)
Async Recalculation on Booking Changes and Telemetry Emission
Given a booking draft previously priced by the calculator When the user edits pickup/return time, swaps an item, adds/removes an item, or changes quantity Then an asynchronous recalculation is triggered within 2 seconds, producing the same payload schema as the synchronous preview with an incremented version And changes in totalAfterCeil ≥ 1 minorUnit emit a deposit_change event containing bookingId, previousTotal, newTotal, delta, consolidationMode, currency, reasonCodesDelta, timestamp And events are idempotent per booking version And every computation emits exposure_computed telemetry with totalExposure, baselineExposure, boostedExposure, riskBucket, bookingStage, and conversionContext And no PII beyond bookingId and anonymized borrower segment is included in telemetry
Synchronous Calculator Response for UI
Given a checkout screen requests a deposit preview via the calculator API with valid items, borrower segment, and booking times When the request is processed Then the API responds within 300 ms p95 and 800 ms p99 with HTTP 200 and the preview payload And validation errors return HTTP 422 with machine-readable codes and no side effects And the response is deterministic for identical inputs within a 10-minute window, honoring an idempotency key
Tapering Reduction Scheduler
"As a repeat borrower, I want my deposit holds to decrease after I demonstrate reliability so that I feel rewarded and not perpetually penalized."
Description

Reduces boosted holds over time based on proven reliability. After each on-time pickup and handoff, applies a decay schedule (e.g., step-down multipliers over N successful transactions or T days) until returning to baseline. Resets or slows decay after a no-show or late pickup. Tracks borrower reliability metrics in a trust profile, respects organizer policies (e.g., minimum decay floor), and updates the risk engine inputs in near real time. Displays upcoming milestones to users and supports backfills for historical completions. All changes are recorded for auditability and customer support.

Acceptance Criteria
Step-Down After On-Time Completion
Given a borrower has an active boosted hold multiplier and a configured transaction-based decay schedule (step size, baseline, organizer min floor) When a booking completes with pickup and handoff both recorded within their on-time windows Then the multiplier is reduced to the next step per schedule without dropping below the greater of baseline and organizer min floor And the borrower trust profile is updated (on_time_completions += 1, last_on_time_completion_at set, reliability_score recalculated) And an immutable audit entry is recorded (before_multiplier, after_multiplier, triggering_transaction_id, event_type=on_time_completion, timestamp, policy_version) And the new multiplier is used by risk engine and booking quotes within 5 seconds of completion
Time-Based Decay With No Adverse Events
Given a borrower has an active boosted hold multiplier and a configured time-based decay schedule (interval_days, step size, baseline, organizer min floor) When the configured interval elapses since the last qualifying change and no no-show or late events occurred in that interval Then the multiplier is reduced to the next step per schedule without dropping below the greater of baseline and organizer min floor And an immutable audit entry is recorded (before_multiplier, after_multiplier, event_type=time_decay, effective_at, policy_version) And the new multiplier is used by risk engine and booking quotes within 5 seconds of the effective time
Penalty on No-Show or Late Event
Given a borrower is mid-decay and penalty mode is configured (reset_to_initial_boost or slow_decay with factors) and grace windows are defined When a no-show occurs or pickup or handoff exceeds the grace window Then if reset_to_initial_boost, set multiplier to initial boost and reset success counters; if slow_decay, adjust step size and/or increase required successes per configuration effective immediately And borrower trust profile metrics are updated (no_shows or lates incremented, reliability_score recalculated) And upcoming milestones are recomputed and visible in UI within 5 seconds And an immutable audit entry is recorded (before_multiplier, after_multiplier, event_type=adverse_event, triggering_transaction_id, penalty_mode, timestamp, policy_version)
Organizer Policy Floors and Caps Respected
Given organizer policies define a minimum decay floor and optional maximum boost cap that override product defaults When applying any decay or penalty adjustment Then the resulting multiplier is clamped to not below max(baseline, organizer_min_floor) and not above organizer_max_cap if configured And the policy source and values used are included in the audit entry (policy_source=organizer, floor, cap) And the risk engine and booking quotes reflect the clamped multiplier And the UI explains the active policy floor when it prevents further decay
Near Real-Time Risk Engine Update
Given the scheduler emits a multiplier change event for a borrower When a booking quote or hold authorization is requested after the event time Then the risk engine uses the most recent multiplier based on event timestamp and policy version And API responses and UI reflect the updated multiplier within 5 seconds of the change And concurrent events are applied deterministically without stale values appearing in quotes
Borrower Milestone Visibility
Given a borrower has an active boosted hold When the borrower views hold details in profile or during checkout Then the UI displays at least the next milestone including next target multiplier, the exact condition to achieve it (date/time for time-based or remaining on-time completions for transaction-based), and an estimated date if applicable And a plain-language explanation shows how to reduce holds and why the current multiplier applies, including any active organizer policy floor And the displayed data matches scheduler state and updates within 5 seconds after relevant events
Backfill Recalculation and Audit Trail
Given historical transactions exist and a backfill is initiated for a borrower over a specified date range When the backfill completes Then the scheduler recomputes the multiplier state as if events were processed in real time using the policy versions effective at each event time And the resulting multiplier matches the value obtained by replaying the event stream deterministically And audit entries are written with source=backfill and are idempotent such that re-running the same backfill range does not create duplicates or change outcomes And the recalculated multiplier is propagated to the risk engine and UI within 5 seconds of backfill completion
Transparent Hold Explanation UI
"As a first-time borrower, I want a simple explanation of a higher deposit hold and how to lower it so that I trust the system and complete my booking."
Description

Adds clear, accessible UI across booking, confirmation, and receipts that explains when and why a hold is boosted, how much higher it is than baseline, and the concrete steps to reduce it (on-time pickups/returns, identity verification, completing bookings during non-peak windows). Uses reason chips and tooltips sourced from the risk engine, supports localized copy, and meets WCAG AA contrast and screen reader requirements. Provides organizer and lender views showing expected holds for incoming bookings. Includes a privacy note on which signals are used and a link to trust profile details.

Acceptance Criteria
Booking Flow: Boosted Hold Banner and Reason Chips
Given the risk engine returns hold_surge=true with reasons [peak_time, first_time_borrower] and baseline_hold=30 and boosted_hold=45 When the borrower views the booking screen Then a surge banner appears above the payment section showing "Hold: $45 (+$15 vs baseline $30)" formatted in the user's locale/currency And the banner displays localized reason chips "Peak time" and "First-time borrower" sourced from risk metadata And each chip exposes a focusable tooltip with an 80–140 character explanation string from risk metadata And a "How to lower this hold" expander lists: complete ID verification (link to verification flow), book outside 5–8pm peak, maintain on-time pickups/returns; each item is actionable And the banner renders within 250ms of receiving the risk response in 95% of sessions And if hold_surge=false, no surge banner is shown and only the baseline hold appears in the payment summary
Confirmation Screen: Surge Rationale, Amount Delta, and Reduction Steps
Given a booking with boosted_hold and a recorded baseline_hold from checkout When the confirmation screen/modal is displayed Then it shows the exact hold amount, delta vs baseline, and localized reason chips identical to those shown at booking And it presents a tapering rule message (e.g., "After 2 on-time handoffs, your hold returns to baseline") and lists next steps with links (ID verify, off-peak suggestions) And a "View your trust profile" link navigates to the trust profile with UTM source=confirm_hold_surge and loads in ≤2s p95 And the displayed amounts match the ledger values to within $0.01 (or minor unit = 1)
Receipt and Email: Transparent Hold Details and Tapering Outcome
Given a booking completes and a receipt (in-app and email) is generated When the receipt is rendered/sent Then it includes: final hold amount, whether a surge applied, reasons (chips or list), and the release/taper outcome with timestamps (released, tapered to baseline, retained pending issue) And if pickup and return were on time, the receipt states the applicable reduction on future holds (e.g., "Next holds reduced to baseline") And the email/localized receipt copy matches the user locale; currency and time formatting follow locale conventions And the amounts equal the payments ledger values; automated test compares fields and passes
Organizer/Lender Dashboard: Expected Holds for Incoming Bookings
Given an organizer or lender opens the Incoming Bookings view When the list loads Then each row shows Expected Hold amount and a Surge badge if boosted, with a hover/focus tooltip listing localized reasons And the list can be filtered by Surge status (All/Surge/No Surge) and sorted by Expected Hold amount And clicking the amount opens a side panel with baseline vs boosted breakdown and borrower guidance steps; no PII beyond reason categories is shown And permissions restrict visibility to hold amounts and reason categories only; attempts to access raw borrower signals are blocked and logged
Localization: Reason Chips, Tooltips, and Guidance Copy
Given the app locale is set to es-ES When the booking, confirmation, and receipt hold UI renders Then all hold-related strings (banner title, chips, tooltips, guidance, privacy note) are displayed in Spanish with no missing keys And currency/number formatting follows locale (e.g., 45,00 €) and time windows use 24-hour format And if a translation is missing, the UI falls back to en-US and logs a missing_key telemetry event And switching locales at runtime updates all hold UI within 500ms without a full-page reload
Accessibility: WCAG AA, Keyboard, and Screen Reader Support
Given a user navigates the hold UI using a keyboard and a screen reader When focus moves through the booking/confirmation screens with a surge present Then all interactive elements (banner, chips, tooltips, expander, links) are reachable in a logical order and operable via Enter/Space; tooltips open on focus and close with Esc And the surge banner is announced with role=region and aria-label indicating importance; screen readers read the hold amount, delta, and each reason chip with accessible descriptions from risk metadata And color contrast for text and chips meets WCAG 2.1 AA (≥4.5:1); automated accessibility checks pass in CI And dynamic changes to surge status are announced via aria-live="polite" without stealing focus
Privacy Note and Trust Profile Deep Link
Given hold explanation UI is displayed on any screen and a surge is present When the user expands the Privacy and signals note Then the note lists the categories of signals used (e.g., on-time history, identity verification status, peak-time flag) matching keys from the risk engine; no raw PII is shown And a "What data informs your hold?" link deep-links to the Trust Profile section about holds and loads in ≤2s p95 And on mobile, the note is collapsed by default and expands within 200ms; state is preserved on navigation back And presence of the note and link is consistent across booking, confirmation, and receipt views
Stripe Hold Orchestration
"As a payments engineer, I want robust Stripe orchestration for variable deposit holds so that holds are accurate, reliable, and released promptly without manual intervention."
Description

Integrates with Stripe to place, adjust, and release deposit preauthorizations based on the calculated hold. Supports incremental authorization or re-authorization on edits, automatic refresh for holds exceeding card networks’ authorization windows, and graceful degradation when authorization limits are reached (e.g., alternative payment prompt or soft block). Ensures idempotency keys, webhook handling for authorization/expiry events, and immediate release on successful handoff. Defines failure and retry policies, dispute-safe logging, and reconciliation reports so finance can match exposure to bookings. Complies with PCI scope boundaries and regional SCA requirements.

Acceptance Criteria
Initial Hold Placement with Hold Surge Applied at Booking
Given a borrower confirms a booking and Hold Surge calculates a deposit hold amount H in currency C When the booking is created Then a Stripe authorization is placed for amount H in C and the Stripe reference (e.g., PaymentIntent ID) is stored on the booking And the borrower is shown the hold amount and a clear explanation of how to reduce future holds And an idempotency key unique to the booking and operation 'hold.create' prevents duplicate authorizations within 24 hours And if regional SCA is required, the borrower is prompted to complete SCA and the hold is only considered successful after authentication And if authorization fails (e.g., insufficient funds or issuer decline), the booking is not confirmed and the borrower is prompted to provide an alternative payment method And no raw card data (PAN/CVV/expiry) is stored or logged; only Stripe tokens/IDs are persisted
Hold Adjustment on Booking Edit (Incremental or Re-authorization)
Given an active authorization H1 exists for a booking When the booking is edited or risk changes and the required hold recalculates to H2 Then if H2 > H1 and incremental authorization is supported, the system increases the authorization to H2 without releasing H1 And if incremental authorization is not supported, the system cancels H1 and creates a new authorization for H2 within 120 seconds And if H2 < H1, the system reduces exposure by releasing the difference via partial reversal where supported or by canceling H1 and authorizing H2 And no funds are captured during any adjustment; only authorizations/voids occur And all adjustment operations use an idempotency key 'booking:{id}:hold.adjust:{opId}' to prevent duplicate changes And if adjustment fails, the booking remains at H1, the borrower is notified to update payment, and an audit log entry is created
Automatic Hold Refresh Before Authorization Window Expiry
Given an active authorization with network expiry at time T When the time is T minus 24 hours and the booking handoff window has not started Then the system re-authorizes for the remaining required exposure and ensures only one active authorization exists after refresh And the borrower is notified that the hold has been refreshed with the new expiry And if refresh requires SCA, the borrower is prompted to authenticate; failure to authenticate follows the refresh failure path And on transient failures, the system retries up to 3 times with exponential backoff of 1 minute, 5 minutes, and 30 minutes And on final failure, the booking is marked 'Hold Failed', a soft block is applied per policy, and the organizer is shielded from no-show risk
Immediate Hold Release on Successful Handoff
Given a successful item handoff is confirmed by organizer scan or system check-in When the handoff confirmation event is received Then the active authorization is canceled within 60 seconds and the booking financial exposure is set to zero And the borrower receives a release confirmation including the Stripe reference And the system records release timestamp and updates the booking timeline And on Stripe API error, the system retries for 15 minutes with backoff; persistent failures trigger an ops alert and hourly retries up to 24 hours
Graceful Degradation on Authorization Limits and Declines
Given an authorization attempt during placement, adjustment, or refresh returns issuer_declined, do_not_honor, or authentication_required that the borrower cancels When the system cannot secure the required hold immediately Then the borrower is prompted to add an alternative payment method or complete SCA And the system offers a one-time 2-hour soft block that reserves the booking without a hold And if no successful authorization is obtained within 2 hours, the booking auto-cancels and inventory is released And a borrower may receive only one soft block per 24-hour period; additional requests are denied And soft-blocked bookings display 'Pending Hold' to organizers and are hidden from other borrowers
Webhook Handling and Idempotency for Authorization Lifecycle
Given Stripe sends events payment_intent.amount_capturable_updated, payment_intent.requires_action, payment_intent.canceled, charge.expired, or charge.captured When events are received by the webhook endpoint Then the Stripe signature is verified with a 300-second tolerance and events are processed exactly once using event.id for idempotency And out-of-order events are handled so final booking state is consistent and capture is never performed for deposit holds And handler failures are retried up to 5 times with exponential backoff; unrecoverable events are moved to a dead-letter queue and ops is alerted And unknown event types are ignored safely and logged for analysis
Daily Reconciliation Reporting and Dispute-Safe Logging
Given the daily reconciliation job runs at 23:55 UTC When the job executes Then it produces a CSV to secure storage with columns: booking_id, borrower_id, surge_reason, hold_amount, currency, stripe_payment_intent_id, status, created_at, expires_at, refreshed_count, last_error, totals_row And the sum of active hold_amounts in the report matches the system's computed exposure within ±0.01 currency units; discrepancies are flagged High severity with tickets created And finance can match 100% of report rows to bookings and Stripe objects via IDs And all Stripe requests/responses are logged with request_id, status code, and redacted payloads; no PAN/CVV/PII beyond Stripe IDs appears in logs
Policy Controls & Overrides
"As an organizer, I want to configure how hold surges apply in my community so that policies reflect local norms without compromising trust."
Description

Provides an admin console for platform and organizer-level configuration of risk weights, peak-time windows, first-time borrower definitions, category caps, and decay schedules. Supports temporary surge policies (e.g., holidays), geo- or community-specific rules, and per-user overrides (waivers or stricter holds) with expiration dates. Includes versioning, change history, preview/simulation against historical bookings, and safe rollout via staged environments and feature flags. Validates configurations to prevent contradictory or unsafe settings.

Acceptance Criteria
Configure Risk Weights, Category Caps, and Decay Schedules
Given I am a platform admin on the Policy Controls console When I set risk weight values for first-time borrower, repeat no-show thresholds, and peak-time multipliers and save Then the system creates a new policy configuration version with a unique version ID and timestamp Given a category cap value is set for a lending category When holds are computed via the preview calculator for items in that category Then the previewed holds do not exceed the configured category cap Given a decay schedule is configured as a percentage reduction per on-time handoff down to a baseline When I preview holds across successive on-time handoffs for the same borrower Then the preview reflects the decay schedule and never drops below the baseline hold
Define Peak-Time Windows and Temporary Surge Policies
Given I define peak-time windows with a specific local timezone and non-overlapping time ranges When I save the configuration Then the stored policy includes the timezone and windows and applies only within those times in preview and rollout Given I create a temporary surge policy with a start and end datetime When the end datetime passes Then the policy auto-expires and is no longer applied to new bookings Given a booking falls within both a peak-time window and a temporary surge period When I preview the deposit hold for that booking Then the combined surge is applied subject to the category cap
Apply Geo- and Community-Specific Rules with Precedence
Given global (platform), organizer-level, and community-level rules exist When a booking is for a user within a community with its own rules Then the community rules override global and organizer-level rules for that booking where defined Given a per-user override exists for the borrower When calculating or previewing the hold Then the per-user override takes precedence over community, organizer, and global rules Given no community rule is defined for a specific field When calculating the hold Then the system falls back to the next broader scope’s value
Per-User Overrides with Expiration and Audit Trail
Given an admin applies a per-user override with a start date and expiration date When the current date is within that range Then the override is applied to the borrower’s holds Given the current date is after the expiration date When calculating the hold Then the override is not applied Given the override is created, edited, or deleted When I view change history for that user Then the audit log shows actor, timestamp, affected user ID, old value, new value, and reason
Configuration Validation Blocks Unsafe or Contradictory Settings
Given I attempt to save a category cap lower than the platform baseline hold When I click Save Then the system blocks the save and shows an error explaining the conflict Given I define overlapping peak-time windows for the same scope When I validate the configuration Then the system requires me to resolve overlaps or supply an explicit precedence rule before saving Given I enter a temporary surge policy without an end datetime When I validate the configuration Then the system blocks the save and requires an end datetime Given I set a risk multiplier outside the allowed range (0.0 to platform max) When I validate the configuration Then the system blocks the save and shows the allowed range Given I click Validate on a configuration When no errors are found Then the system shows Validation Passed and enables Save
Versioning, Change History, and Rollback
Given I save any policy change When the save completes Then a new immutable policy version with unique ID, author, timestamp, diff summary, and changelog message is created Given multiple policy versions exist When I select a prior version and click Rollback Then the system creates a new version identical to the selected one and records the rollback in history Given I view change history When I filter by scope (platform, organizer, community, user) and date range Then the list shows matching entries with before and after values
Preview/Simulation and Staged Rollout via Feature Flags
Given I select a policy version and a historical date range When I run a simulation against historical bookings Then the system outputs for each booking the old hold, new hold, delta, and any cap or override applied Given simulation results exceed a configured threshold (e.g., more than 10% average increase for a community) When the run completes Then the system flags the result and requires explicit acknowledgment before allowing rollout Given a policy version is not yet rolled out When I enable its feature flag in a staging environment or selected pilot communities Then only those environments or communities use the new policy and others remain on the previous version Given an issue is detected post-rollout When I disable the feature flag Then the system immediately reverts affected scopes to the previous active version without data loss
Notifications, Receipts, and Decision Audit
"As a customer support agent, I want a clear audit of hold decisions and user-facing receipts so that I can explain outcomes and resolve disputes quickly."
Description

Sends timely in-app and email notifications when a boosted hold is applied, adjusted, or released, and includes reason codes and steps to reduce future holds. Booking receipts show baseline vs. boosted hold amounts and expected release timing. A support-facing audit view surfaces the risk signals, policy version, and timeline of changes for each booking, enabling quick resolution of disputes. Aggregated analytics track conversion, no-show rate, average hold amount, and exposure by risk tier to validate that surges deter flakes without harming reliable users.

Acceptance Criteria
Boosted Hold Applied Notification (In-App & Email)
Given a booking where Hold Surge applies a boosted deposit hold When the boosted hold is calculated and set Then the borrower receives an in-app notification within 60 seconds that includes: baseline hold amount, boosted hold amount, reason code(s), steps to reduce future holds, and a link to the hold policy And the borrower receives an email with the same content within 5 minutes And notification delivery status (sent, delivered, opened) is logged against the booking And users who opted out of marketing emails still receive the transactional email And no duplicate notifications are sent for the same event (idempotent by booking+event ID)
Hold Adjustment and Release Notifications
Given a booking with an active boosted hold When the hold amount is adjusted downward due to improved risk state or system tapering Then the borrower receives an in-app notification within 60 seconds and email within 5 minutes showing old vs. new hold amount, effective timestamp, reason code(s), and updated steps to reduce holds And the booking timeline shows the adjustment with actor (system/agent) and policy version Given a booking that completes on-time handoff and return When the hold is released Then the borrower receives an in-app notification within 60 seconds and email within 5 minutes that the hold is released, with expected bank release timing and reference ID And release events are logged once per booking state change (no duplicates) And if release processing fails, a failure notification is sent and the system retries per policy
Receipt Shows Baseline vs. Boosted Hold and Timing
Given a borrower confirms a booking during a period where Hold Surge applies When the receipt is generated (in-app and email) Then the receipt displays baseline hold amount, boosted hold amount, total amount held, and expected release date/time in the borrower’s timezone And the receipt lists reason code(s) that triggered the boost and a clear “How to lower holds” section with at least three actionable steps And all amounts match the payment ledger and are shown in the booking’s currency with correct formatting And the in-app receipt is accessible from the booking detail view and the email contains a deep link to the same view
Support Audit View: Risk Signals, Policy Version, Timeline
Given a support agent opens a booking in the admin console When viewing the Hold Surge audit panel Then the agent sees: the risk signals evaluated (names and values), the computed risk tier, the policy version ID and effective date, and a chronological timeline of hold events (applied, adjusted, released) with timestamps, actor, old/new hold amounts, and reason codes And the audit data is read-only, immutable, and time-zone normalized to UTC with local time hover And the view is searchable by booking ID, borrower ID, lender ID, and date range, and exportable to CSV And sensitive PII beyond what’s needed for case resolution is redacted
Analytics Dashboard: Conversion, No-Show, Avg Hold, Exposure by Risk Tier
Given product and ops users access the analytics dashboard When selecting a time range and optional filters (neighborhood, item category, borrower cohort) Then the dashboard shows: booking conversion rate (confirmed/initiated), no-show rate (missed handoffs/confirmed), average hold amount, and total hold exposure by risk tier And each metric is broken down by risk tier and borrower cohort (first-time vs. returning) And data freshness is under 2 hours and coverage > 99% of eligible events for the selected period And users can export the aggregated metrics as CSV And metric definitions are documented in-line with tooltips
Actionability: Steps to Reduce Future Holds Are Contextual
Given a borrower receives any Hold Surge notification or receipt When reason code(s) are present Then the message includes a contextual “How to lower holds” section mapping each reason code to specific actions (e.g., verify ID, complete on-time handoffs, add trusted references) And the section includes a direct link to the profile/trust settings page and estimated time to complete each action And clicks on the guidance links are tracked with event names and booking/user IDs for measurement

Arrival Check-In

A quick “On My Way” check-in inside the pickup window confirms intent. Missed check-ins trigger a short grace timer and warn both parties before the booking rolls to the waitlist. Lenders gain predictability; borrowers build a visible reliability streak that lowers future holds.

Requirements

One-Tap On My Way Check-In
"As a borrower, I want to quickly confirm I’m on my way within my pickup window so that the lender knows I’m committed and my booking stays active."
Description

Delivers a single-tap On My Way action available only during the borrower’s active pickup window to confirm intent and keep the booking live. Displays a live countdown to window end, disables outside window bounds, and prevents duplicate check-ins. On confirmation, instantly updates the booking state, notifies the lender, and pins the trip in the borrower’s itinerary. Integrates with the live calendar so window shifts immediately adjust the check-in eligibility. Supports push and in-app notifications, and provides SMS deep-link fallback when the app is not foregrounded. Handles poor connectivity by queuing the action for up to two minutes and reconciling server state on reconnect.

Acceptance Criteria
Check-In Eligibility Within Pickup Window
Given a borrower has an active booking with a pickup window from Tstart to Tend When the current time is >= Tstart and < Tend Then the On My Way action is enabled and tappable Given the current time < Tstart or >= Tend When the borrower views the booking Then the On My Way action is disabled and labeled with the reason (e.g., Opens at HH:MM or Window ended) Given multiple overlapping bookings exist When viewing a specific booking Then eligibility is evaluated solely against that booking’s window
Live Countdown to Window End
Given a booking is within its pickup window ending at Tend When the borrower is on the booking detail screen Then a countdown displays remaining time to Tend (MM:SS) and updates at least once per second And the countdown reaches 00:00 exactly at Tend based on server-synchronized time (±2s) And the countdown visibility is hidden/disabled when outside the window
Duplicate and Idempotent Check-In
Given the borrower taps On My Way once When the tap is processed Then subsequent taps within 60 seconds are ignored at the client and no duplicate network requests are sent And the server endpoint is idempotent by bookingId, returning success with existing state if the action was already recorded And if the borrower attempts from a second device, the UI reflects already checked-in within 5 seconds
Immediate State Update and Lender Notification
Given the borrower successfully confirms On My Way When the server acknowledges the check-in Then the booking state changes to On My Way in the borrower app within 1 second of response And the trip is pinned to the borrower’s itinerary immediately And the lender receives a push and in-app notification within 5 seconds containing booking item, borrower name, and ETA window And an audit event with timestamp and actor is recorded for reliability tracking
Real-Time Eligibility on Calendar Window Shifts
Given the live calendar adjusts the pickup window for a booking When the new window is applied on the server Then the borrower’s eligibility state (enabled/disabled) updates in-app within 2 seconds without app restart And if the window shifts such that current time becomes within the window, the On My Way action becomes enabled And if the window shifts such that current time falls outside, the action becomes disabled with updated reason And if the borrower already checked in before the shift, the check-in remains valid and the booking stays live
Offline Queue and Server Reconciliation
Given the device has poor or no connectivity during the pickup window When the borrower taps On My Way Then the app shows a Sending pending state and queues the request for up to 2 minutes And if connectivity is restored within 2 minutes, the queued action is sent and the UI updates per success or failure And if still offline after 2 minutes, the pending state is cleared, the UI returns to pre-check-in, and an error is shown And upon reconnect, the app reconciles with server state so that if the server already shows On My Way, the UI reflects it without duplicating the action
Push, In-App, and SMS Deep-Link Fallback
Given a check-in event occurs and the recipient app (lender or borrower) is not foregrounded When push delivery fails or is not opened within 10 seconds Then an SMS with a secure deep link is sent to the recipient’s verified phone number And opening the deep link routes to the booking detail screen And if within the borrower’s pickup window, the On My Way action is shown enabled; otherwise it is disabled with the correct reason And for the lender, the booking state reflects On My Way with timestamp and borrower info
Geo-Verified Check-In (Optional)
"As a lender, I want the check-in to confirm the borrower is near the pickup location so that I can prepare confidently without unnecessary waiting."
Description

Enhances check-in with an optional, privacy-preserving location verification that confirms the borrower is within a configurable radius of the pickup point at the time of check-in. Requests foreground location permission just-in-time, degrades gracefully if declined, and stores only coarse geohash with accuracy metadata. Applies accuracy thresholds and retry prompts when GPS is weak and falls back to time-only confirmation if verification fails repeatedly. Lender sees a simple Verified badge; exact coordinates are never exposed. All flows remain accessible without location for users who opt out, preserving inclusivity while improving trust for those who opt in.

Acceptance Criteria
Just-in-Time Opt-In and Foreground Location Permission
Given a borrower has an active booking within the pickup window and taps "On My Way" When Geo-Verified Check-In is available and the user elects to enable it Then the app requests only foreground location permission at that moment with clear purpose text referencing pickup verification And then the app does not request background location permission And then no location prompt is shown prior to tapping "On My Way" And then if permission is already granted, no new prompt is displayed
Geo Verification Within Configurable Radius
Given the pickup point has a verification radius of 100 meters And given the device reports a location fix with accuracy <= 100 meters When the borrower checks in within 100 meters of the pickup point Then the check-in is marked Geo-Verified And then the lender-facing booking view shows a "Verified" badge And then the borrower receives a confirmation indicating Geo-Verified status
Weak GPS Accuracy: Retry and Fallback to Time-Only
Given the device reports accuracy > 100 meters or no fix is available When the borrower attempts Geo-Verified check-in Then the app prompts the user to retry up to 2 times with guidance to improve signal And then each retry waits up to 10 seconds for an accuracy improvement And then if after retries accuracy remains > 100 meters or no fix is available, the app completes a time-only check-in (not Geo-Verified) and informs both parties
Privacy-Preserving Storage and No Coordinate Exposure
Given any check-in attempt (Geo-Verified or time-only) When the check-in record is persisted or logged Then raw latitude/longitude are not persisted or written to logs And then only a coarse geohash (precision <= 6 characters) and reported accuracy (in meters) are stored for Geo-Verified events And then lender and borrower UIs never display coordinates or a map for the check-in And then external notifications, exports, and analytics exclude precise coordinates (geohash/accuracy only for Geo-Verified events)
Opt-Out or Permission Declined Flow
Given the borrower has opted out of geo verification or denied location permission When they tap "On My Way" during the pickup window Then the check-in completes successfully as time-only without requesting location And then no "Verified" badge is shown to the lender And then the borrower's reliability streak updates as with any successful check-in
UI Indicators and Internal Auditability
Given a Geo-Verified check-in has been recorded When viewing booking details as the lender Then a single "Verified" badge is visible without revealing coordinates or distance And then as the borrower, the check-in detail indicates "Geo-Verified" And then an internal audit record contains timestamp, method = geo or time-only, accuracy bracket, and coarse geohash; no raw coordinates
Configurable Verification Radius per Pickup Point
Given an organizer sets the pickup point verification radius to 150 meters (allowed range 50–300 meters, default 100 meters) When a borrower checks in for a booking associated with that pickup point Then Geo-Verified pass/fail uses the configured 150-meter radius And then changing the radius later affects only future bookings; existing bookings retain the radius captured at booking creation
Grace Timer and Dual-Sided Alerts
"As a borrower, I want clear reminders and a short grace period if I miss the initial check-in so that I have a fair chance to keep my booking."
Description

Starts an automatic, short grace timer when a borrower misses the initial check-in at window start. Sends borrower a reminder and lender a heads-up, displaying a countdown across both apps. If the borrower checks in before grace expiry, the booking proceeds unchanged; otherwise the booking is marked at-risk and prepared for auto-release. Timer defaults are platform-defined with safe bounds and can be adjusted by product operations without code deploys. Integrates with push, SMS, and email for reliable delivery, with idempotent alerts to avoid duplicates. All transitions are atomic and resilient to race conditions or retries.

Acceptance Criteria
Start Grace Timer and Display Countdown on Missed Check-In
Given a confirmed booking with pickup window starting at T0 and no borrower check-in by T0 When the system detects the missed check-in at T0 Then a grace timer starts immediately with duration equal to the current platform default And a countdown is displayed on both borrower and lender apps within 5 seconds of timer start And the countdown is based on server time and remains accurate across app restarts and network reconnects And only one active grace timer exists per booking
Proceed Unchanged When Borrower Checks In During Grace Period
Given a booking with an active grace timer When the borrower taps "On My Way" before the timer expires Then the booking remains in the Booked state with the original pickup window unchanged And the countdown banner is removed from both apps within 5 seconds And any scheduled auto-release task for this booking is canceled And no At Risk flag is set and no waitlist actions are triggered
Mark Booking At-Risk and Prepare Auto-Release on Grace Expiry
Given a booking with an active grace timer and no borrower check-in When the timer reaches zero Then the booking status is set to At Risk And the system prepares for auto-release by enqueuing a single idempotent release task for the booking And both apps update to show At Risk state and the countdown is removed within 5 seconds
Dual-Sided Alerts: Borrower Reminder and Lender Heads-Up
Given a missed check-in that starts a grace timer When alerts are dispatched Then the borrower receives a reminder via push, SMS, and email within 60 seconds of timer start And the lender receives a heads-up via push, SMS, and email within 60 seconds of timer start And both apps display a visible countdown banner for the duration of the grace period
Idempotent Alert Delivery Across Push, SMS, and Email
Given duplicate event deliveries or retries for the same grace timer start When the notification service processes them Then each user receives at most one push, one SMS, and one email for that grace instance And subsequent duplicates are suppressed using a consistent deduplication key And transient send failures are retried per channel policy without creating duplicate deliveries
Operations-Adjustable Timer Defaults with Safe Bounds
Given safe bounds minBound and maxBound are configured for grace timer duration When product operations updates the default duration via the admin console Then values within [minBound, maxBound] are saved and applied to new grace timers within 1 minute of save And attempts to set values outside bounds are rejected with a validation error and the previous default remains in effect And existing active grace timers continue with their originally assigned durations
Atomic Transitions Under Concurrency and Retries
Given concurrent events where a borrower check-in arrives near grace expiry and a release/expiry job executes When the system processes these events Then exactly one consistent outcome is committed using atomic transaction semantics And if the check-in timestamp is less than or equal to the grace expiry (server time), the booking proceeds unchanged and any At Risk flag or release task is not applied And if the check-in timestamp is greater than the grace expiry, the booking is marked At Risk and any late check-in is rejected with an informative message And repeated deliveries of the same event do not create duplicate state changes, tasks, or alerts
Auto Roll-to-Waitlist and Calendar Reflow
"As a waitlisted borrower, I want to be automatically offered the item when the original borrower misses check-in so that I can borrow without manual coordination."
Description

Automatically releases a booking to the waitlist when the grace timer expires without check-in, notifying the next eligible borrower to claim within a brief acceptance window. Updates the lender’s calendar in real time, freeing the slot and preventing overlaps with existing smart pickup windows. Applies item-specific rules, respects lender blackout settings, and rolls forward until a borrower accepts or inventory closes. Ensures deposit holds are voided for the original borrower and pre-authorized for the new borrower, keeping payment state consistent. All state changes are transactional and replay-safe to avoid double allocation.

Acceptance Criteria
Grace Expiry Triggers Auto Roll and Next-Borrower Notification
Given a confirmed booking with a pickup window and a grace timer When the borrower does not check in before grace expiry Then the booking state changes to Released-To-Waitlist and the original borrower’s reservation is revoked And the next eligible waitlisted borrower is selected per item rules and priority ordering And the next borrower is notified via in-app and at least one fallback channel (email or SMS) within 5 seconds And an acceptance window equal to the configured value (e.g., 10 minutes) starts for that borrower And notifications include claim-by timestamp, item name, pickup window, and primary actions to Claim or Decline And all actions are timestamped with server time and recorded in the audit log
Calendar Reflow Prevents Overlaps and Respects Blackouts
Given a booking is released to the waitlist Then the lender’s calendar frees the corresponding slot and publishes updates to subscribed clients within 3 seconds And the freed slot does not overlap with existing smart pickup windows or lender blackout settings And if the next borrower accepts, the same slot is re-blocked for them within 1 second to prevent double booking And attempts to create overlapping appointments during reflow are rejected with HTTP 409 and no state change And calendar feeds (web and mobile) reflect the new state within one refresh cycle or 5 seconds, whichever is sooner
Payment Holds Transition on Roll (Void Original, Pre-Auth Next)
Given the original borrower has an active deposit hold When the booking is released due to grace expiry Then the original hold is voided within 15 seconds and the payment state becomes Void without capture When the next borrower accepts within their acceptance window Then a new pre-authorization is created for the correct deposit amount before confirming the booking And if pre-authorization fails, the booking does not confirm for that borrower, the failure is logged, the borrower is skipped, and the roll continues to the next And at no time do two active holds exist simultaneously for the same booking And payment events are correlated to booking IDs with idempotency keys to prevent duplicates
Rolling Through Waitlist Until Acceptance or Inventory Close
Given one or more waitlisted borrowers exist When the current acceptance window expires without acceptance Then the system automatically advances to the next eligible borrower and repeats the notify-and-wait cycle And borrowers failing eligibility checks (e.g., blacklist, reliability threshold, conflicting bookings) are skipped without notification and logged with reason codes And the roll continues until a borrower accepts or until the pickup window ends, at which point the inventory closes and the slot is freed And each borrower receives at most one acceptance window per booking And the lender receives a single consolidated update when the slot is finally reallocated or closed
Transactional Integrity and Idempotent Replay Safety
Given concurrent events (grace expiry, borrower late check-in, lender cancellation, message retry) Then state transitions are atomic and idempotent, producing at most one active booking for the slot And replaying the same expiry or acceptance message with the same idempotency key does not create duplicate notifications, bookings, or payment operations And under a forced service restart during reflow, on recovery the system resumes from the last committed state and does not double-allocate the item And telemetry shows zero double allocations and zero orphaned holds in a soak test of 1,000 concurrent simulations And every state transition writes an append-only audit record with versioning to support conflict detection
Late Check-In Edge Handling Around Grace Expiry
Given a borrower taps “On My Way” during the grace timer Then the auto roll does not execute and the booking remains confirmed Given a borrower taps “On My Way” at or after the exact grace expiry moment (server time) Then the roll proceeds and the check-in is rejected with a Late Check-In error And server time is authoritative; client timestamps do not prevent expiry And both parties receive status updates reflecting the final outcome within 2 seconds
Reliability-Based Deposit Adjustment
"As a frequent borrower, I want my reliability streak to lower my deposit holds so that borrowing becomes cheaper as I build trust."
Description

Calculates and maintains a borrower reliability streak based on on-time check-ins, missed check-ins, and no-shows, then adjusts future deposit hold amounts accordingly. Shows a simple, positive streak indicator in profile and checkout, explaining how reliable behavior reduces holds. Uses decay and sampling rules to prevent gaming, caps daily contributions, and distinguishes lender-cancelled events from borrower faults. Integrates with Stripe to set authorization amounts at booking time and to update amounts when streak thresholds cross. Provides product ops controls for tuning weights, thresholds, and caps without code changes.

Acceptance Criteria
Streak Calculation with Check-In Outcomes and Grace Rules
- Given a booking with a pickup window, when the borrower taps "On My Way" within the configured window, then the event is recorded as On-Time Check-In and adds the configured positive weight to the reliability streak. - Given a borrower does not check in before the window ends, when the grace timer expires without a check-in, then the event is recorded as Missed Check-In and applies the configured negative weight to the streak and sends warnings to both parties. - Given a borrower neither checks in nor arrives by the end of the grace period, then the event is recorded as No-Show and applies the configured heavier negative weight to the streak. - Given a lender cancels before the pickup window opens, then the event is excluded from streak calculations and labeled Lender-Cancelled. - Given the parties mutually reschedule before the pickup window opens, then the original event is neutral (no effect on streak) and the new booking is treated independently. - Then all outcome records persist with timestamp, actor attribution, and outcome type, and are queryable for audit.
Deposit Hold Determination at Booking via Stripe Authorization
- Given a borrower initiates a booking, when the system evaluates their current reliability streak, then it calculates a deposit hold amount using the configured tier thresholds and weights. - Given the borrower confirms checkout, when the payment method is present, then the system creates a Stripe authorization for the calculated amount with an idempotency key and stores the Stripe auth ID on the booking. - Then the UI shows the deposit hold amount before confirmation and in the booking receipt. - If Stripe authorization fails, then the booking is not created and the user sees a clear error with retry instructions. - Then the booking record persists the reliability tier and deposit amount used for authorization.
Re-Authorization on Streak Threshold Change Prior to Pickup
- Given a booking with an existing deposit authorization, when the borrower’s reliability streak crosses a configured tier threshold before the pickup window opens, then the system recalculates the required deposit. - When the recalculated deposit is lower, then the system partially releases the authorization to the lower amount and notifies the borrower. - When the recalculated deposit is higher, then the system attempts to increase the authorization; if the increase fails, the booking moves to Needs-Action state, the borrower is prompted to update payment, and pickup is blocked until resolved. - Then all authorization adjustments are performed with idempotency and are logged with before/after amounts and timestamps.
Streak Decay and Sampling Anti-Gaming
- Given the reliability streak is computed, when older events are present, then their contribution is reduced using the configured decay function (e.g., exponential with configured half-life). - Given a borrower exceeds the configured sampling threshold of eligible events within the rolling evaluation window, then only a deterministic sample (using a configured sampling rate and hash function) contributes to the streak. - Then the effective sample size and decay weights used for the borrower are surfaced in an internal metrics endpoint for verification.
Daily Contribution Cap Enforcement
- Given multiple borrow events occur for the same borrower on the same calendar day (in the borrower’s timezone), when computing streak contribution, then only the first N outcomes (configured) contribute and all additional outcomes that day have zero weight. - Then the system exposes in the borrower’s activity log which events counted toward the daily cap and which were capped. - Then cap enforcement applies regardless of lender or item and is applied before decay and sampling.
Reliability Indicator and Explanation in Profile and Checkout
- Given a borrower has a computed reliability streak, when viewing their profile, then a positive, simple indicator is shown with copy explaining how reliability reduces deposit holds and links to learn more. - Given the borrower is in checkout, then the indicator and the computed deposit preview for this booking are displayed prior to confirmation, with accessible alt text and localization. - Given a new borrower without enough samples, then the UI displays a “New” state and the default deposit amount; no streak is shown. - Then the indicator text and thresholds are configurable via CMS/ops settings without code deployment.
Ops Controls for Weights, Thresholds, and Caps
- Given an authorized ops user, when they update weights, thresholds, caps, decay, and sampling settings in the admin console, then the changes are validated (type and bounds), versioned, and applied to new calculations within the configured propagation SLA. - Then a dry-run mode allows previewing deposit amounts and streak outcomes for selected borrower histories under proposed settings without persisting changes. - Then all configuration changes are audited with actor, old/new values, timestamp, and rationale; only users with the appropriate role can modify settings.
Lender Controls and Overrides
"As a lender, I want control over grace timers and overrides so that the system matches my availability and risk tolerance."
Description

Gives lenders configurable controls for Arrival Check-In, including selectable grace timer within safe bounds, preferred notification channels, and a per-booking override to hold the reservation beyond grace when circumstances warrant. Presents clear defaults to minimize setup while allowing advanced users to tailor behavior. Overrides record the reason and duration, update borrower expectations in-app, and are auditable by support. All settings are scoped per lender with sensible inheritance to organizational accounts, and changes take effect only for future bookings unless explicitly applied to in-flight ones.

Acceptance Criteria
Grace Timer Configuration Within Safe Bounds
Given a lender opens Arrival Check-In settings When they attempt to save a grace timer below 5 minutes or above 30 minutes Then the system blocks the save and displays an inline error: "Grace timer must be between 5 and 30 minutes" Given a lender selects a grace timer increment not divisible by 5 When they save Then the system blocks the save and prompts valid options: 5, 10, 15, 20, 25, 30 minutes Given a lender selects a valid value (e.g., 15 minutes) When they save Then the setting persists and the summary view reflects the selected value
Default Settings for New Lender Accounts
Given a new lender account with no prior configuration When the lender first views Arrival Check-In settings Then defaults are pre-populated: grace timer = 10 minutes; notification channels = in-app + email And the lender can save without changes in a single action (≤2 clicks) And no errors are shown
Preferred Notification Channels Selection and Delivery
Given a lender edits preferred notification channels When they enable SMS and disable email and save Then subsequent Arrival Check-In alerts for that lender's bookings are sent via SMS only (no email) And an in-app notification is displayed Given a lender attempts to enable SMS without a verified phone number When they try to save Then the system blocks the save and shows guidance to verify the number
Per-Booking Override to Extend Hold Beyond Grace
Given an in-flight booking within the pickup window When the lender selects "Extend hold", enters a reason, and chooses a duration between 5 and 120 minutes in 5-minute increments, then confirms Then the booking's hold expiration updates by the chosen duration And the system records actor, timestamp (UTC), original expiry, new expiry, reason, booking ID in an immutable log And the borrower sees the updated pickup deadline in-app within 10 seconds with a banner "Reservation extended to [time]" And notifications are sent to both parties per their current channel preferences Given an override is active When the lender attempts to create a second overlapping override Then the system requires confirmation to replace the existing override and versions the audit record
Apply Settings Changes Only to Future Bookings
Given a lender updates the grace timer in settings When a new booking is created after the save time Then the new booking uses the updated grace timer Given bookings that were created before the settings change When they enter the pickup window with no explicit action by the lender Then they retain their original grace configuration Given existing in-flight bookings When the lender selects "Apply to in-flight bookings" and confirms the scope Then only the selected bookings update to the new grace timer And each update is recorded in the audit log with actor, timestamp, old value, and new value
Organizational Inheritance and Lender-Level Overrides
Given a lender belongs to an organization with org-level defaults When the lender has no personal settings for grace timer or notification channels Then the lender's effective settings inherit the org defaults Given the same lender later sets a personal grace timer When a new booking is created for that lender Then the personal value takes precedence over the org default Given the organization updates its defaults after that When bookings are created for lenders who still inherit Then those bookings use the new org defaults And lenders with personal overrides are unaffected
Support Auditability of Overrides and Settings Changes
Given a booking with one or more overrides and settings changes When a support user with proper permission opens the booking audit view Then they can see a chronological, read-only trail including: actor ID, role, timestamp (UTC), entity (setting or override), old value, new value, reason (if provided), and booking/user IDs And the trail is tamper-evident (no edits; new entries only) And the view supports filtering by date range and event type
Audit Trail and Dispute Timeline
"As support staff, I want a complete timeline of check-in events so that I can resolve disputes quickly and fairly."
Description

Captures a complete, immutable timeline of events for each booking, including window updates, reminders sent, check-in attempts and results, geo-verification status (if enabled), grace start and expiry, and waitlist roll actions. Displays a readable timeline to both parties and a detailed view to support with delivery receipts and error codes. Redacts sensitive data while keeping sufficient evidence for fair decisions. Data retention follows policy with secure archival, and exports are available for compliance requests. Timeline enables quick resolution of no-show disputes and informs reliability scoring adjustments when manual corrections are warranted.

Acceptance Criteria
Comprehensive Event Capture for Arrival Check-In Bookings
Given an active booking with Arrival Check-In enabled And geo-verification is enabled for the booking When any of the following occur: pickup window update, automated reminder sent (SMS/push/email), borrower check-in attempt (success/fail), geo-verification result returned, grace timer start/expiry, waitlist roll action executed Then the booking timeline records exactly one entry per event with: event_type, UTC timestamp (ms precision), actor (system/borrower/lender), outcome/status, reason_code (if applicable), channel and provider_message_id (for communications), and booking_id And repeated deliveries/retries do not create duplicates (idempotency by provider_message_id) And every new entry increments a monotonically increasing sequence_number by 1
Append-Only Immutability and Tamper Detection
Given an existing booking timeline with N entries When new events or manual corrections occur Then existing entries remain unchanged (no updates or deletes) And a new correction entry is appended with: performed_by user_id and role, reason_code, pre_value_hash, post_value_hash, and timestamp And the timeline maintains a hash chain (prev_hash, entry_hash) such that end-to-end verification succeeds And any alteration, deletion, or reordering causes hash verification to fail and raises a SECURITY_TAMPER_DETECTED alert
Participant-Facing Readable Timeline with Redactions
Given a borrower or lender opens the booking timeline When the timeline loads Then entries render in chronological order with localized timestamps, human-readable labels, and markers for check-in status, grace countdown, and waitlist roll events And sensitive details are redacted: precise coordinates replaced with “geo-verified within pickup area”, contact identifiers masked, and provider IDs/error codes hidden And the timeline loads within 200 ms (p95) for up to 200 entries on a 4G connection
Support Detailed Timeline View with Delivery Receipts and Error Codes
Given a user with Support Agent role opens the booking timeline When the detailed view is requested Then each entry exposes metadata including delivery receipts (SMS SID, Push GUID, Email Message-ID), delivery status and error codes, geo-verification method and confidence score, device info, and system error stack (if any) And PII is minimally revealed per policy: IPs truncated to /24, Stripe tokens masked except last 4, GPS rounded to geofence centroid And access to this view is authorization-checked and writes an AUDIT_ACCESS log with agent_id, timestamp, purpose, and booking_id
Dispute Workflow Integration and Reliability Scoring Adjustments
Given a no-show dispute is opened for a booking When the dispute case is viewed Then the system highlights timeline checkpoints: last reminder sent, check-in attempts with outcomes/timestamps, geo-verification status at T-10/T0/T+5 minutes, grace start/expiry, and waitlist roll action And the system produces a rules-based suggestion (e.g., borrower checked in within window -> borrower not at fault) And when an agent applies a manual correction, a correction entry is appended with reason_code and evidence_reference; reliability_score is recalculated within 60 seconds; deposit hold status updates per policy; both parties’ timelines reflect the change
Data Retention, Archival, and Legal Hold Compliance
Given retention_days is configured (e.g., 365) and a booking is closed When retention_days elapse without an active legal_hold Then the timeline is encrypted (AES-256) and moved to archival storage; the online view shows an “Archived” badge; first access retrieves within 3 seconds (p95) And entries containing PII are minimized per policy; any purge writes a PURGE entry preserving non-PII evidentiary hashes And if legal_hold is active, archival proceeds but purge/minimization is deferred until the hold is lifted
Role-Aware Compliance Export with Integrity Verification
Given a Compliance Officer requests an export for a booking within a date range When the export is generated Then the system produces: a JSON file of all timeline entries including hash chain, a human-readable PDF summary, and an evidence ZIP (delivery receipts, error logs) And both JSON and PDF are signed with the platform signing key; signature and hash verification succeed using the published public key And the export is available within 5 minutes and logged with requestor_id, time, scope, and artifact hashes And participant-initiated exports exclude sensitive metadata by default, while compliance exports include full evidence except secret keys, OAuth tokens, and full payment credentials

Early Release

Lets lenders trigger an early handoff to the next borrower if the current one misses check-in or the grace period. Calendars auto-adjust, deposits update, and notifications quietly route the new pickup—preventing dead time and keeping projects on schedule.

Requirements

Missed Check-in & Grace Timer Engine
"As a lender, I want the system to automatically detect missed check-ins and grace expirations so that I can hand off to the next borrower without manual monitoring."
Description

Implements a rules-driven timer that detects when a current borrower misses their scheduled check-in and when the configured grace period elapses. Upon threshold breach, the engine marks the booking as eligible for Early Release, emits domain events, and updates the booking state. It supports per-item and per-organization grace settings, handles time zones, daylight saving shifts, and ensures idempotent evaluations to avoid duplicate triggers. Integrates with the booking calendar, notification service, and policy module to enforce HOA/organizer-specific rules.

Acceptance Criteria
Eligibility after Grace Period Elapses
Given a current booking with scheduled_check_in_at = 2025-09-01T10:00:00-04:00 and effective_grace_period_seconds = 900 and no borrower check-in recorded When the engine evaluates time >= 2025-09-01T10:15:00-04:00 Then booking.early_release_status = "Eligible" and booking.status transitions to "MissedCheckIn" And a single EarlyReleaseEligible domain event is emitted for this booking And the evaluation timestamp is persisted for auditability
Per-Item vs Organization Grace Setting Precedence
Rule 1: If an item-level grace period is configured, the engine uses that value for the booking Rule 2: If no item-level value exists, the engine uses the organization-level grace period Rule 3: If neither is configured, the engine applies a system default grace period of 600 seconds and records a config_source = "system_default" in the evaluation metadata
Idempotent Evaluation Prevents Duplicate Triggers
Given a booking already marked early_release_status = "Eligible" with EarlyReleaseEligible event emitted and dedup_key persisted When the engine re-evaluates the same booking N>1 times after eligibility Then no additional EarlyReleaseEligible events are emitted (event_count remains 1) And booking state remains unchanged And the same dedup_key is reused to prevent downstream duplication
Correct Time Zone and DST Handling (Spring Forward)
Given a booking in America/Los_Angeles with scheduled_check_in_at = 2025-03-09T01:55:00-08:00 and effective_grace_period_seconds = 600 and no borrower check-in When the engine evaluates across the DST spring-forward transition (02:00–03:00 local time does not exist) Then the grace breach occurs at 2025-03-09T03:05:00-07:00 (PDT) and not at a non-existent local time And eligibility and event emission are computed against the correct instant and time zone offset
Domain Events Emitted with Complete, Validated Payload
Given a booking becomes eligible for Early Release When the engine emits EarlyReleaseEligible Then the payload includes: event_type, booking_id, item_id, organization_id, borrower_id, next_booking_id (if any), scheduled_check_in_at (ISO 8601 with zone), effective_grace_period_seconds, evaluation_time (ISO 8601 with zone), effective_time_zone, reason = "missed_check_in_grace_elapsed", dedup_key (stable), occurrence_id (UUID v4) And the payload passes schema validation and PII redaction rules And the event is published exactly once to the message bus topic = "booking.early_release.eligible" with delivery confirmation
Policy Module Enforcement on Early Release
Given an organization policy rule denies early release during quiet hours 22:00–07:00 local And a booking’s grace period elapses at 22:30 local When the engine requests a policy decision for the booking Then the decision = "deny" And booking.early_release_status = "Denied" with reason_code = "quiet_hours" And no EarlyReleaseEligible event is emitted; instead EarlyReleaseDenied is emitted with the policy rationale
Early Release Trigger Controls (Manual & Auto)
"As a lender, I want a one-tap Early Release with an impact preview so that I can keep items circulating confidently when a borrower no-shows."
Description

Provides lenders with a clear, single-action control to trigger Early Release, alongside auto-trigger rules that activate after grace expiry. The flow includes an impact preview (affected bookings, new pickup window, deposit status), confirmation, and safe rollback if downstream steps fail. Exposes feature flags for phased rollout, rate limiting to prevent abuse, and emits analytics/telemetry for adoption tracking. Accessible via mobile and web, with permission checks to ensure only item owners or authorized organizers can initiate.

Acceptance Criteria
Feature Flag, Permission, Rate Limiting, and Telemetry Enforcement
Given the Early Release feature flag is disabled for the tenant or item, When a user views a booking, Then the Early Release control is hidden and auto-trigger rules are not scheduled. Given the feature flag is enabled and the viewer is the item owner or an authorized organizer, When the booking is eligible, Then the Early Release control is visible and enabled. Given a user is not the owner or an authorized organizer, When they attempt to call the Early Release API, Then the request is rejected with HTTP 403 and an audit record is written. Given more than 3 manual Early Release attempts have been made on the same item within 24 hours, When another attempt is made, Then the request is rejected with HTTP 429, no state changes occur, and a rate-limit message is shown. Given any Early Release attempt occurs, When the request is processed, Then an analytics event "early_release_attempt" is emitted with properties {trigger_type, actor_role, item_id, booking_id, outcome}. Given an Early Release completes successfully, When processing finishes, Then an analytics event "early_release_completed" is emitted with correlation_id and timing metrics.
Manual Early Release Trigger (Mobile/Web)
Given a booking where the current borrower has missed check-in or is within the grace window and a next booking exists, When the owner or authorized organizer views the booking on web or mobile, Then a single-action "Early Release" control is shown with a consistent label and iconography. Given the control is visible, When the user taps or clicks it, Then an impact preview modal or sheet opens within 2 seconds at the 95th percentile. Given there is no next booking or the grace window has not begun, When the user views the booking, Then the control is disabled or hidden and a tooltip explains eligibility rules. Given the preview is open, When the user cancels, Then no changes are made and the modal closes.
Auto-Trigger After Grace Period Expiry
Given auto-trigger rules are enabled and the current borrower has not checked in by the grace expiry, When the grace period ends, Then the system initiates Early Release within 3 minutes without manual action. Given there is no eligible next booking or the minimum buffer cannot be met, When the grace period ends, Then auto-trigger is skipped and an audit entry records the reason. Given the feature flag is disabled or rate limiting would be exceeded, When the grace period ends, Then auto-trigger does not run and is logged with outcome "suppressed". Given auto-trigger runs, When it completes, Then an audit log entry exists with type "auto_triggered", booking_id, item_id, timestamp, and correlation_id.
Impact Preview Before Confirmation
Given an eligible booking, When the user opens the Early Release preview, Then it displays current booking end time, next booking new pickup window start and end, affected booking IDs, and deposit statuses for current and next borrowers. Given the preview is shown, When data changes server-side before confirmation, Then the UI warns that the schedule changed and forces a recompute before allowing confirmation. Given the preview is shown, When computing the pickup window, Then the result respects the configured minimum buffer and overlap resolution rules. Given the preview cannot be computed, When an error is returned by the API, Then an error state is displayed and the Confirm action is disabled.
Execution: Calendar Adjustments and Next Pickup Window
Given a user confirms Early Release, When the system executes, Then the current booking's end time is set to the release timestamp and the next booking's start is moved to the computed early pickup window start while respecting the minimum buffer. Given execution completes, When the lender and next borrower view their calendars, Then the updated times are visible within 5 seconds and no overlapping bookings exist for the same item. Given no eligible next booking exists at execution time, When the system attempts to update, Then the operation aborts with no calendar changes and returns error code ER-NEB-001.
Deposit Hold Update and Notifications Routing
Given Early Release is executing, When updating deposits, Then the next borrower's deposit hold is created or adjusted in Stripe for the new pickup window using idempotency keys and no duplicate holds exist. Given the current borrower missed check-in, When Early Release executes, Then the current borrower's deposit status is updated according to policy and is not incorrectly released. Given execution succeeds, When it completes, Then the next borrower is notified via their configured channels with the new pickup window within 60 seconds and the lender receives a confirmation. Given the payment provider returns an error, When processing deposits, Then execution stops, changes are rolled back, a clear error is shown, and an incident is logged.
Safe Rollback and Idempotency with Error Surfacing
Given any downstream step fails during Early Release execution, When the failure occurs, Then all mutated data (calendar, deposits, notifications queue) is rolled back to the pre-trigger state atomically. Given a rollback occurs, When the user returns to the booking view, Then the UI reflects the original schedule and an error banner with a correlation ID is shown. Given the same Early Release request is retried with the same idempotency key within 10 minutes, When processing again, Then no duplicate side effects occur and the final state is consistent. Given a failure occurs, When system logs are inspected, Then an audit trail exists including actor, trigger_type, reason, and correlation_id.
Calendar Reflow & Availability Recalculation
"As the next borrower, I want my pickup window to move earlier automatically when possible so that I can start my project sooner without coordinating manually."
Description

Automatically recalculates and applies new availability windows when an Early Release is triggered. Shifts the next borrower’s pickup window forward while respecting buffer times, travel time, and existing commitments. Resolves conflicts via deterministic rules, updates shared calendars/ICS feeds, locks affected slots to prevent race conditions, and notifies dependent services via events. Ensures atomic updates across bookings to avoid overlaps and maintains a consistent view across all clients.

Acceptance Criteria
Early Release Reflows Next Pickup While Respecting Buffers and Travel
Given an asset with configured buffer and travel-time constraints And the current borrower misses check-in or the grace period expires And a next borrower has a scheduled pickup later the same day When the lender triggers Early Release Then the next borrower’s pickup start is moved forward to the earliest feasible time that satisfies buffer, travel-time, and existing commitments And the booking duration remains unchanged And no overlap is created with other bookings or commitments
Deterministic Conflict Resolution for Overlapping Reflows
Given two or more future bookings would overlap after reflow When reflow is computed Then bookings are ordered by creation timestamp ascending And earlier-created bookings retain their positions And later-created bookings are shifted to the next available windows that satisfy all constraints And if no feasible window exists that day, the booking moves to the earliest next-day window per asset availability And the same input schedule always yields the same reflowed output
Atomic Multi-Booking Update with Consistent Client Views
Given reflow affects multiple bookings and shared calendars When the system applies updates Then all changes are committed atomically in a single transaction And no client observes a partial state at any time And if any write fails, the entire reflow is rolled back with no persisted changes And after success, web and mobile clients display the new schedule within 5 seconds of reconnect or next poll And the public API returns the reflowed schedule immediately after commit
Slot Locking and Concurrency Control During Reflow
Given two Early Release triggers occur concurrently for the same asset When reflow executes Then the system acquires locks on all affected time slots and bookings And only one reflow proceeds while others wait or retry without data races And no duplicate or overlapping bookings are created And lock TTL prevents deadlocks and all locks are released on completion or rollback
Shared Calendar and ICS Feed Reflect Reflow
Given reflow completes successfully When fetching the asset’s ICS feed and shared calendar endpoints Then updated event start/end times are available within 60 seconds And rescheduled instances increment SEQUENCE and update DTSTAMP And cancellations are represented with STATUS:CANCELLED where applicable And UIDs remain stable per booking
Event Notifications to Dependent Services Are Accurate and Idempotent
Given reflow completes successfully When events are published Then one ReflowApplied event is emitted per affected booking with correlation and causation IDs And each event includes asset ID, booking ID, old/new time ranges, and version And an idempotency key enables safe consumer retries And events are published after transaction commit and within 2 seconds of completion
Timezone and DST-Safe Reflow Calculation
Given the asset’s timezone differs from the viewer’s timezone And a reflow crosses a daylight saving time boundary When availability and ICS entries are recalculated Then stored times are normalized in UTC with correct offsets for the asset timezone And client-rendered local times show no +/-1 hour drift And ICS includes VTIMEZONE and correct DTSTART/DTEND offsets
Deposit Hold Re-auth & Liability Transfer
"As an organizer, I want deposit holds to transfer seamlessly to the next borrower so that liability and risk are correctly covered during early handoffs."
Description

Integrates with Stripe to re-authorize deposit holds at Early Release time for the next borrower while releasing or canceling the current borrower’s hold. Handles SCA challenges, card failures, partial captures, and retries with backoff. Ensures funds availability before calendar changes are finalized, and rolls back the release if payment preconditions fail. Records all payment intents and ledger entries for compliance and reconciliation, and supports different deposit policies per HOA or item category.

Acceptance Criteria
Successful Re-Authorization and Liability Transfer on Early Release
Given a lender triggers Early Release for an item with a scheduled next borrower And the next borrower’s payment method is on file and valid When the system requests a Stripe deposit hold re-authorization for the resolved policy amount Then the re-authorization is approved and a new PaymentIntent is confirmed And the current borrower’s existing hold is released or canceled within 2 seconds of the new hold confirmation And liability transfers to the next borrower effective at the early release handoff timestamp And the booking calendar updates only after the new hold confirmation succeeds And borrower and lender notifications are sent only after the calendar update succeeds And the end-to-end operation completes within 5 seconds at p95
Strong Customer Authentication (SCA) Challenge Handling
Given the re-authorization requires Strong Customer Authentication per Stripe When the Early Release is initiated Then the system enters a Pending SCA state and presents the next borrower with an SCA prompt via Stripe (link or in-app) And upon SCA success within 10 minutes, the re-authorization confirms and the workflow proceeds to finalize as in the successful transfer scenario And upon SCA failure or timeout, the Early Release is aborted, no calendar changes are made, the current borrower’s hold remains intact, and the failure reason is recorded
Funds Unavailable: Rollback Early Release
Given the re-authorization attempt is declined for insufficient funds or a non-retryable card error And all configured retry attempts (if any) are exhausted When the Early Release workflow evaluates preconditions Then the Early Release is rolled back; no calendar changes occur And the current borrower’s deposit hold remains active And lender and organizer are notified of the failure with the decline reason code And no pickup notification is sent to the next borrower And the decline code and correlation ID are recorded for audit
Retry with Exponential Backoff on Transient Processor Errors
Given a transient processor or network error occurs during re-authorization (e.g., HTTP 5xx, timeout) When the system performs the re-authorization Then it retries up to 3 times with exponential backoff of 2s, 4s, and 8s plus ±20% jitter And stops retrying on first success or upon encountering a non-retryable error code And records each attempt (timestamp, error category, duration) for observability And surfaces the final outcome to the workflow: success proceeds to finalize; failure triggers rollback
Partial Capture and Release Sequencing for Current Borrower
Given the current borrower has policy-allowed charges to be captured from their deposit (e.g., late fee, damage) When Early Release is triggered Then the system captures the authorized amount up to the policy-defined partial capture limit before releasing the remaining hold And releases any remaining authorization immediately after a successful partial capture And proceeds to re-authorize the next borrower’s deposit for the resolved policy amount And ensures capture/release and new re-authorization are atomic; if the capture fails, the Early Release is aborted and no calendar changes occur
Per-HOA and Item Category Deposit Policy Enforcement
Given the item is associated with an HOA and a category, each with defined deposit policies When resolving the deposit amount and currency for re-authorization Then policy precedence is applied as: Item-specific override > HOA policy > Category default And the re-authorization uses the resolved amount and currency And an audit record stores the policy source, policy version, and resolved amount And automated tests verify at least two distinct policy combinations and the precedence outcomes
Audit Trail and Idempotency for Payment and Ledger Events
Given Early Release triggers payment operations, webhooks, and ledger entries When duplicate triggers or webhook retries occur Then the system uses a per-Early-Release correlation ID to ensure idempotency; no duplicate holds, releases, captures, notifications, or ledger lines are created And all PaymentIntent/Charge IDs, policy references, actors, item and borrower IDs, timestamps, and correlation IDs are recorded immutably And a reconciliation export including these fields can be generated on demand and passes referential integrity checks And audit records are available within 60 seconds of the event completing
Adaptive Notification Routing & Quiet Hours
"As a borrower, I want timely and respectful notifications about an early pickup option so that I don’t miss an accelerated handoff."
Description

Delivers context-aware notifications to the current borrower (missed check-in/grace warnings), lender (Early Release opportunity/status), and next borrower (accelerated pickup) via push, SMS, and email. Respects quiet hours, user preferences, and locale/time zone; includes escalation and fallback channels. Uses templated, localized content with compliance links, and deduplicates messages to reduce noise. Integrates with the in-app inbox, supports deep links to acceptance flows, and logs delivery/open events for analytics.

Acceptance Criteria
Missed Check-in Escalation (Borrower, Outside Quiet Hours)
Given a borrower has an active reservation, has not completed check-in by the configured deadline, and the current time is outside the borrower’s quiet hours When the missed check-in event is detected Then send a context-aware notification to the borrower via the highest-priority eligible channel per preferences within 60 seconds And log the send attempt with timestamp, channel, template_id, locale, and correlation_id And escalate to the next eligible channel if no delivery receipt or open is recorded within the configured escalation window, stopping when any channel records delivery or open And deduplicate so the borrower receives at most one notification per channel per event within a 15-minute coalescing window And render localized content in the borrower’s locale with compliance links per channel And post a copy to the in-app inbox thread with a deep link to the check-in flow
Missed Check-in Deferred (Borrower, Within Quiet Hours)
Given a borrower misses check-in during their configured quiet hours When the missed check-in event is detected Then queue the external notification for delivery at the earliest allowed send time after quiet hours in the borrower’s locale/time zone And immediately create a silent in-app inbox entry (no push/SMS/email) with a deep link to the check-in flow And cancel the queued external notification if the borrower completes check-in before the send time And on DST transitions, compute the send time using the borrower’s IANA time zone to avoid off-by-one-hour errors And log the queue, cancel, and send outcomes for analytics
Lender Early Release Opportunity Prompt
Given a borrower has exceeded the configured grace period and the reservation is eligible for Early Release When the lender is outside their quiet hours Then send a notification with a deep link to the Early Release screen including item, borrower initials, and the proposed accelerated window And on lender approval via the deep link, update reservation status and calendars within 30 seconds and send a confirmation And send only one reminder if there is no action within the configured interval; total prompts must not exceed two per event across all channels And deduplicate across channels within a 15-minute window and post to the in-app inbox And log action (approve/ignore), timestamps, and channels
Next Borrower Accelerated Pickup Notice
Given Early Release is approved and a next borrower exists When the next borrower is outside their quiet hours Then send a notification with a deep link to accept or decline the accelerated pickup window And on acceptance, update the calendar and send confirmation within 30 seconds; on decline or no response by the configured deadline, retain the original schedule and stop reminders after one nudge And if the event occurs during quiet hours, queue until quiet hours end and create a silent inbox entry immediately And deduplicate across channels and include localized, compliant content And log send, delivery, open, and accept/decline events with correlation to the Early Release event
Channel Preference, Fallback, and Opt-in Compliance
Given each user has channel preferences and opt-in status per channel When selecting channels for a notification Then attempt only channels that are both preferred and compliant with opt-in and tenant policy And if the top-priority channel fails (e.g., invalid push token, SMS undeliverable), fall back to the next eligible channel and record the failure reason And process SMS STOP/UNSTOP and email unsubscribe immediately; reflect preference changes within 60 seconds for pending and future sends And store all send times in UTC, evaluating quiet hours with the user’s time zone at dispatch time
Template Localization and Deep Link Integrity
Given localized templates exist for supported locales (en, es, fr minimum) When rendering a notification Then validate required variables (item_name, pickup_time, action_link, compliance_links) before send; if any are missing, do not send and emit an alert And format dates/times and numbers per user locale; fall back to default locale only when a translation key is missing and log a warning And include signed deep links with reservation_id, user_id, and expiry; opening the link routes to the correct screen on iOS/Android/Web within 2 seconds of app launch And append analytics tracking parameters without breaking deep link routing
Global Deduplication and Throttling Guardrails
Given multiple related events occur for the same reservation and recipient When generating outbound notifications Then coalesce into a single user-facing notification per recipient per event type within a configurable coalescing window (default 15 minutes) And enforce a hard cap of no more than 3 notifications per user per hour originating from this requirement; excess are queued or dropped with audit reasons And if a higher-priority event supersedes a lower-priority queued notification, replace the queued one and log the replacement
Next-Borrower Acceptance & Pickup Confirmation
"As the next borrower, I want to accept an earlier pickup window or keep my original time so that the schedule still fits my availability."
Description

Presents the next borrower with a simple accept/decline prompt for the earlier pickup window, allowing them to choose from suggested times within the new window. If they decline or do not respond within a configurable SLA, the system reverts to the original schedule or offers the slot to the subsequent borrower. Updates queue positions, enforces caps on response time, and syncs confirmations to the calendar and notifications services. Supports accessibility and mobile-first interactions.

Acceptance Criteria
Early Release Prompt Delivered to Next Borrower
Given a lender triggers an early release due to a missed check-in or expired grace period And there is at least one subsequent borrower in the queue When the system creates an early pickup offer Then the next borrower receives an accept/decline prompt via in-app within 5 seconds and via their configured channel(s) (push/email/SMS) within 30 seconds And the prompt clearly displays the new pickup window start and end in the borrower's timezone And only suggested pickup times within the new window are shown And access to the offer is restricted to the targeted borrower and expires upon SLA expiry
Accepts and Selects Suggested Pickup Time Within New Window
Given the borrower opens the early pickup offer When they tap "Accept Early Pickup" Then they must select one of the suggested times that falls within the new window And the system validates the selection against lender availability, location constraints, and buffer rules And upon confirmation, the acceptance is recorded with offer_id, user_id, selected_time, and timestamp And the borrower's booking updates to the selected pickup time And a confirmation screen is shown and a confirmation notification is sent And the offer is marked as accepted and no further responses are allowed
Declines Early Pickup Offer
Given the borrower opens the early pickup offer When they tap "Decline" Then the system applies the configured decline policy (revert_to_original or offer_to_next) deterministically And if revert_to_original, all bookings revert to their pre-offer times with no queue changes And if offer_to_next, the offer is sent to the subsequent borrower in the queue within 5 seconds And the declining borrower retains their original booking and position And an audit log event early_release.declined is recorded with offer_id, user_id, and timestamp
No Response Within SLA Triggers Fallback
Given an early pickup offer has been sent And a response SLA duration is configured for the community When the SLA elapses without an accept or decline Then the offer status is set to expired And the configured fallback is applied (revert_to_original or offer_to_next) And late responses are rejected with a user-visible message "Offer expired" And affected parties are notified of the outcome And queue positions and availability are recalculated and persisted And the configured SLA is validated against system min/max bounds
Queue, Calendar, and Notifications Sync on Acceptance
Given an offer is accepted with a selected pickup time When the system commits the acceptance Then queue positions are updated to reflect the accepting borrower moving to the new earlier slot And subsequent borrowers’ relative positions and times are adjusted accordingly And the shared calendar event is updated within 5 seconds and reflects the new pickup time, location, and participant And notifications are sent to the lender, accepting borrower, and impacted subsequent borrowers And system events are emitted (early_release.accepted, booking.updated) with idempotency keys to prevent duplicates And no double-bookings exist for the same item and time range
Accessibility and Mobile-First Interaction Compliance
Given a borrower uses the early pickup offer flow on a mobile device or with assistive technology When they navigate the prompt and choose an action Then all interactive targets are at least 44x44 dp and keyboard-focusable with visible focus indicators And text and control contrast ratios meet WCAG 2.1 AA (text 4.5:1, non-text 3:1) And all controls have accessible names/roles and state changes are announced via ARIA live regions And the flow is fully operable without gestures (keyboard-only) and supports screen readers And the prompt loads in under 2 seconds on a 3G-equivalent network and under 200 KB transfer size
Suggested Times Generation and Validation
Given an early pickup window start and end are defined And lender availability, system buffer time, location hours, and borrower timezone are known When the system generates suggested pickup times Then at least 3 options are produced when feasible, all within the early window and respecting buffers and availability And options are aligned to 15-minute increments and sorted soonest-first And options do not overlap existing bookings or blackout periods And if fewer than 1 valid option exists, the offer indicates "No times available" and disables acceptance
Audit Trail & Dispute Resolution Artifacts
"As support staff, I want a complete, exportable timeline of an Early Release so that I can investigate and resolve disputes quickly and fairly."
Description

Creates an immutable event log capturing check-in timestamps, grace period milestones, trigger source (auto/manual), calendar adjustments, notification receipts, and all payment/deposit events. Surfaces a human-readable timeline for lenders, borrowers, and support, with export to CSV/JSON for case handling. Applies retention policies per jurisdiction (e.g., GDPR), supports redaction requests, and includes correlation IDs to tie events across services for quick debugging and fair dispute resolution.

Acceptance Criteria
Immutable Event Log on Early Release Trigger
Given an active booking with a defined grace period, When a lender manually triggers early release, Then an audit event is appended with fields: event_id, correlation_id, booking_id, item_id, actor_id, trigger_source=manual, occurred_at=ISO8601 UTC, previous_event_hash, and status=success. Given an active booking, When the system auto-triggers early release after grace period expiry, Then an audit event is appended with trigger_source=auto and includes grace_period_start, grace_period_end, and grace_period_expired_at timestamps. Given network retries, When the same event_id is submitted twice, Then only one audit record exists and the API responds idempotently with 200 and the same resource identifier. Given the audit log, When a tamper verification is requested, Then the chain verification endpoint returns valid and any update attempt results in a new correction event without altering the original record. Given normal load, When audit events are written, Then p95 write latency is <= 300ms and a persisted read-back confirms durability.
Human-Readable Timeline for Stakeholders
Given a lender, current borrower, next borrower, and support agent with valid roles, When they open the booking timeline, Then each sees a chronologically ordered, human-readable list of events with local timezone display and hover/copy showing exact UTC timestamps. Given PII and payment metadata, When the borrower or lender views the timeline, Then sensitive tokens and emails are masked, while support with elevated scope sees unmasked fields permitted by policy. Given 100 timeline events, When the timeline loads, Then p95 render time is <= 1s and the UI supports filter by event type and date range and paginates at 50 events per page. Given access control, When an unauthorized user attempts to view a timeline, Then the system returns 403 and no event metadata is leaked.
Export Timeline to CSV and JSON
Given a booking timeline with filters applied, When the user selects Export CSV, Then a CSV file is generated within 30s for up to 10,000 events respecting the filters and RFC 4180 formatting. Given the same filtered set, When the user selects Export JSON, Then a JSON file is generated with an array of events including correlation_id, event_id, event_type, occurred_at, actor, and redaction markers. Given an export completes, When the download is presented, Then the filename includes booking_id and date, and a SHA-256 checksum is provided for integrity verification. Given role-based field visibility, When a borrower exports, Then masked fields remain masked; When a support agent with scope support:pii exports, Then permitted fields are unmasked.
Jurisdiction-Based Retention and Redaction Compliance
Given a user subject to GDPR with a configured retention period of 24 months, When the retention timer elapses, Then affected events are purged or anonymized per policy and no longer visible in timelines or exports for standard roles. Given a valid data subject redaction request, When the request is approved, Then PII fields in affected events are redacted within 30 days and a RedactionApplied event is appended referencing the original event_ids. Given redacted events, When a timeline or export is generated, Then redacted fields display as [REDACTED] and hash-chain verification remains valid via overlay/tombstone events without altering original immutable records. Given a legal hold, When retention would otherwise purge events, Then events are retained until the hold is lifted and this exception is auditable.
Notification and Deposit Events Capture
Given early release triggers notification to the next borrower, When email, SMS, or push is sent, Then an audit event records provider, message_id, recipient_id, channel, send_timestamp, and template_id. Given a delivery webhook arrives, When status updates to delivered or failed, Then a new audit event records status, received_at, and error_code if any and links to the original notification via correlation_id. Given a deposit hold, release, or charge occurs in Stripe, When the payment event fires, Then an audit event records payment_intent_id, amount, currency, action=hold|release|charge, reason, and outcome. Given a failed payment, When the attempt is declined, Then decline_code and failure_reason are captured and surfaced in the human-readable timeline.
Calendar Adjustment Audit and Consistency
Given an early release reassigns pickup from borrower A to borrower B, When calendar entries are updated, Then audit events record previous_time_range, new_time_range, resource_id, and affected_booking_ids for both borrowers. Given calendar and notification updates propagate, When measured under normal load, Then p95 propagation time from trigger to updated calendar visible in UI and notification dispatch is <= 2s. Given the consistency check endpoint is called, When it evaluates the booking and related calendars, Then it returns consistent=true for all related entities or lists anomalies with actionable codes. Given the original borrower checks in after early release, When the system detects the conflict, Then a ConflictDetected event is logged and the configured resolution rule is applied and audited.

Flake Cooldown

Progressive limits kick in after repeated no-shows: narrower pickup windows, restricted peak hours, or higher minimum trust requirements—paired with a clear path to restore full access via a few on-time handoffs. Protects the community while coaching better behavior.

Requirements

No-Show Event Tracking & Flake Score
"As an organizer, I want no-shows to be tracked and scored fairly over time so that cooldowns are applied consistently and only when warranted."
Description

Instrument booking lifecycle events (reservation, pickup window open, handoff confirmations, timeouts) to detect no-shows and late/early behaviors, then compute a rolling, decaying flake score per user. Weight recent events more heavily, handle both pickup and return no-shows, and distinguish organizer- vs borrower-caused failures. Persist the score with audit trails and timestamps, expose a read model for policy evaluation, and ensure privacy-safe data retention. This creates the factual basis to trigger cooldown tiers consistently across Sharehood.

Acceptance Criteria
Pickup No-Show Detection
Given a booking with pickup_window_start_at and pickup_window_end_at in UTC and status "reserved" And no pickup_handoff_confirmed event exists for the booking When current_time >= pickup_window_end_at Then the system emits a pickup_no_show event with fields {event_id, booking_id, borrower_user_id, occurred_at, cause="borrower"} And the event is persisted exactly once (idempotent on {booking_id, "pickup_no_show"}) And the booking status transitions to "pickup_no_show" And the event appears in the audit trail within 60 seconds of window end And if pickup_window_end_at is extended before expiry, detection uses the latest end time and does not emit a no-show for the superseded window
Return No-Show Detection
Given a booking with return_window_start_at and return_window_end_at in UTC and item_status "with_borrower" And no return_handoff_confirmed event exists for the booking When current_time >= return_window_end_at Then the system emits a return_no_show event with fields {event_id, booking_id, borrower_user_id, occurred_at, cause="borrower"} And the event is persisted exactly once (idempotent on {booking_id, "return_no_show"}) And the booking status transitions to "return_no_show" And if a return_handoff_confirmed is recorded after return_window_end_at but before the no-show emission, the system emits a late_return event instead and does not emit return_no_show
Early/Late Behavior Classification
Given configurable thresholds: pickup_early_threshold_minutes=15, pickup_late_grace_minutes=10, return_late_grace_minutes=15 When a pickup_handoff_confirmed occurs Then classify and emit exactly one of: pickup_early if occurred_at < pickup_window_start_at - pickup_early_threshold; on_time_pickup if pickup_window_start_at - pickup_early_threshold <= occurred_at <= pickup_window_start_at + pickup_late_grace; late_pickup if pickup_window_start_at + pickup_late_grace < occurred_at <= pickup_window_end_at; late_pickup_after_window if occurred_at > pickup_window_end_at and no no-show was emitted When a return_handoff_confirmed occurs Then classify and emit exactly one of: on_time_return if occurred_at <= return_window_end_at + return_late_grace; late_return if occurred_at > return_window_end_at + return_late_grace and no no-show was emitted And classification events include delta_minutes relative to window and are persisted idempotently
Organizer vs Borrower Attribution
Given a failure or lateness event candidate for booking B When an organizer_action in {cancel, reschedule, change_location} exists after window_start and before effective window_end that makes the handoff impractical Then set event.cause="organizer" and exclude it from borrower flake score inputs When no such organizer_action exists Then set event.cause="borrower" When an authorized organizer submits an attribution_override within 24 hours of the event with reason_code and free_text Then the system updates event.cause, recalculates the user's flake score within 5 minutes, and appends an audit entry capturing {event_id, old_cause, new_cause, actor, timestamp} And borrowers cannot override their own attribution
Rolling Decaying Flake Score Computation
Given a user U and an event stream with types {pickup_no_show, return_no_show, late_pickup, late_return, on_time_handoff, pickup_early} And a configurable half_life_days H (default 30) When any contributing event is added, cause changed to "borrower", or removed Then compute S = min(100, round( Σ(weight(type) * 100 * 2^(-age_days/H)), 1 )) using weights: pickup_no_show=1.0, return_no_show=1.4, late_pickup=0.2, late_return=0.4, on_time_handoff=-0.05, pickup_early=0.0; events with cause="organizer" contribute 0 And enforce 0 <= S <= 100 And publish updated S to the read model within 2 seconds p95 and 5 seconds p99 of the triggering change And apply nightly recomputation to reflect decay even without new events
Data Persistence, Audit, and Retention Compliance
Given any lifecycle, classification, attribution change, or score update event When the event is persisted Then an immutable audit record is appended with fields {event_id(UUIDv4), event_type, booking_id, borrower_user_id, organizer_user_id(optional), cause, occurred_at(UTC), recorded_at(UTC), actor_type, source_service, idempotency_key(optional), previous_values(for score updates), checksum} And all event timestamps are stored in UTC with millisecond precision And write operations are idempotent for the same idempotency_key within 24 hours And personal data beyond user_id is not stored in event payloads And retention is enforced: raw event payloads retained 395 days (configurable); after retention, ancillary PII fields are redacted; score snapshots older than 395 days are pruned except the latest per month aggregate And upon a verified user erasure request, all events and scores for that user are deleted within 7 days and removed from read models
Read Model Exposure for Policy Evaluation
Given the cooldown policy engine requests reliability data for user U When querying the read model Then the response includes {user_id, current_score, last_updated_at, counts_30d {pickup_no_show, return_no_show, late_pickup, late_return, on_time}, attribution_breakdown_30d {borrower_caused, organizer_caused}} And the API enforces access control: internal policy services and authorized staff can read any user; a borrower can read only their own metrics And the read model reflects new events within 3 seconds p95 of persistence and supports 99th percentile read latency under 100 ms for cached users And responses contain no PII beyond user_id And booking-scoped audit events can be retrieved by booking_id with pagination and date filters
Progressive Cooldown Policy Engine
"As an organizer, I want progressive restrictions to automatically apply based on behavior so that the community is protected while allowing responsible members to keep borrowing."
Description

Create a configurable rules engine that maps flake score tiers to specific restrictions such as narrower pickup windows, blocked peak-hour booking, and higher minimum trust level requirements. Evaluate rules in real time during search and booking, with location- and community-level overrides. Support tier escalation and automatic decay over time, conflict resolution when multiple rules apply, and clear reason codes. Configuration should be data-driven (e.g., JSON or admin UI) to enable rapid iteration without code changes.

Acceptance Criteria
Real-Time Rule Evaluation at Search and Booking
Given a user with flake score S and location/community context When the user performs item search or initiates a booking Then the policy engine evaluates all applicable rules within <=150 ms p95 and returns a deterministic restriction set for each item/timeslot And each restriction includes a reason code and human-readable message And if a booking attempt violates any restriction, the booking is blocked with the specific reason code and alternative eligible timeslots are suggested And the response includes a correlation ID and rule version for auditability
Tier-Based Pickup Window Narrowing
Given a configuration mapping flake tiers to pickup_window_minutes and min_buffer_minutes When a user in tier T views availability or attempts to book Then the engine computes pickup windows using the configured width for T and never wider than the default And overlapping windows are trimmed to respect min_buffer_minutes and existing reservations And the UI payload marks adjusted windows with source=cooldown and includes the effective window width And bookings outside the computed windows are rejected with reason code COOLDOWN_WINDOW_NARROWED
Peak-Hour Booking Restriction Enforcement
Given peak-hour intervals are defined per weekday and time range for a location/community And a tier rule indicates peak_hours_blocked=true When a user in that tier attempts to book a timeslot that overlaps any peak-hour interval Then the booking is rejected with reason code COOLDOWN_PEAK_HOURS_BLOCKED and the message lists the next three off-peak alternatives And search results annotate peak-hour slots as ineligible for that user And admins can override peak hours at the community level, which immediately changes eligibility
Minimum Trust Level Requirement Gate
Given an item has a base min_trust_level X and the user's tier adds delta D per configuration When a user with trust score T attempts to book the item Then booking is permitted only if T >= X + D Else the booking is blocked with reason code COOLDOWN_TRUST_TOO_LOW and the response includes current trust T and required trust (X + D) And the error payload links to actions that increase trust (e.g., ID verify, on-time handoffs)
Tier Escalation, Decay, and Rehabilitation
Given flake events are recorded (e.g., no-show, late arrival beyond threshold) with timestamps When a user accrues N flake events within a rolling window of W days (per configuration) Then the user escalates one tier effective immediately and restricted capabilities apply on next decision And escalation is capped at max_tier When the user completes M consecutive on-time handoffs within D days, or no flake events occur for P days (decay period) Then the tier reduces by one level down to baseline And every tier change emits an immutable audit event (old_tier, new_tier, trigger, timestamp, actor/system) and is idempotent on retries
Conflict Resolution with Location and Community Overrides
Given global rules, community-level overrides, and location-specific overrides may all apply When two or more rules target the same restriction dimension (e.g., window width, peak hours, trust delta) Then precedence is resolved as location > community > global And if multiple rules at the same precedence conflict, the most restrictive outcome is selected And the engine returns the effective rule set plus an ordered list of reason codes reflecting precedence and restriction strength And a debug trace indicating overridden rules is available via logs and admin API
Data-Driven Configuration and Hot Reload
Given rules are defined as JSON and editable via admin UI with schema validation When an admin publishes a valid change Then the configuration is versioned, audit-logged, and propagates cluster-wide within <=60 seconds without service restart And the rule version used is attached to each evaluation response When an invalid configuration is submitted Then it is rejected with detailed validation errors and no changes are applied And admins can roll back to any prior version with immediate effect
Earn-Back Pathway & Tier Decay
"As a borrower who was restricted, I want a clear way to earn back full access by completing on-time handoffs so that I can return to normal use."
Description

Define a transparent restoration path that reduces cooldown tiers after members complete a configurable number of consecutive on-time handoffs. Include time-based tier decay, progress tracking, and optional educational prompts (etiquette tips/acknowledgements) that must be completed to unlock the next tier. Surface milestones and remaining steps to the user profile and booking flow, and ensure the policy engine reacts instantly as progress is made.

Acceptance Criteria
Consecutive On-Time Handoffs Reduce Cooldown Tier
Given a member is in cooldown tier T > 0 and the earn-back threshold is N consecutive on-time handoffs, When the member completes the Nth consecutive on-time handoff, Then the member’s cooldown tier decreases by 1 immediately and the streak counter resets to 0 for the next tier. Given the member has a current on-time streak S < N, When the member completes an on-time handoff, Then S increments by 1 and is reflected on the profile and booking flow within 5 seconds. Given any no-show or late pickup/return occurs before reaching N, When the incident is recorded, Then the streak resets to 0 and no tier change occurs. Given the member completes multiple qualifying handoffs across different items on the same day, When their cumulative streak reaches N, Then only one tier decrement is applied per threshold crossing. Given the member is already at tier 0, When additional on-time handoffs occur, Then no further tier decrement occurs and the streak display is hidden or marked complete.
Time-Based Tier Decay Without Handoffs
Given time-based decay is enabled and set to D days without incidents, When D full days elapse since the member’s last no-show/late incident with no new incidents recorded, Then the cooldown tier decreases by 1 at 00:00:00 UTC on the next evaluation tick and never below tier 0. Given multiple contiguous periods of D days elapse without incidents, When each period completes, Then at most one tier decrement occurs per period and never below tier 0. Given the member has an active open booking with a pending handoff at the scheduled decay time, When the handoff completes or expires, Then the decay evaluation runs immediately and applies if criteria are met. Given users operate in different time zones, When displaying decay timing, Then user-facing timestamps are localized while computation uses UTC for consistency.
Progress Milestones Surface in Profile and Booking Flow
Given a member is in any cooldown tier T > 0, When they view their profile or initiate a booking, Then they see current tier T, on-time streak S of N required, remaining steps to next tier (N − S), and any required educational prompt status in both views. Given progress changes due to a handoff completion or decay, When the event is persisted, Then the UI updates within 5 seconds or on next navigation/refresh and shows the new tier and streak. Given the member is not in cooldown (tier 0), When viewing the same areas, Then the module indicates full access (tier 0) and hides earn-back steps. Given accessibility requirements, When the progress module renders, Then key information is exposed to assistive technologies and maintains WCAG AA contrast (≥ 4.5:1).
Educational Prompts Gate Tier Unlock
Given a tier requires an educational prompt, When the member reaches the threshold to drop a tier via streak or decay, Then the tier change enters a Pending state and the prompt is presented immediately (or on next session) with a clear CTA to complete. Given the member completes the prompt (views content and submits acknowledgement or passes a 1–3 question check), When submission succeeds, Then the pending tier decrement is applied within 2 seconds and recorded with timestamp and content version. Given the member dismisses or abandons the prompt, When they next visit profile or booking flow, Then the prompt reappears until completion and no tier change is applied. Given the member previously completed the prompt for the same tier version, When the threshold is reached again, Then no additional prompt is required for that tier version.
Policy Engine Reacts Instantly to Progress
Given a qualifying event occurs (on-time handoff reaching N, decay, or prompt completion), When the event is persisted, Then the policy engine recalculates booking rules and applies the new tier’s restrictions/permissions within 2 seconds. Given the member attempts a booking within 2 seconds of a qualifying event, When the booking is submitted, Then a pre-confirmation revalidation uses the latest tier to prevent stale-rule confirmation. Given a rule evaluation runs, When it completes, Then an audit record is stored containing member ID, prior tier, new tier, trigger event type, and timestamp.
Admin Config and Auditability
Given an authorized admin updates earn-back settings (N, D, min/max tiers, prompt requirements by tier), When the change is submitted, Then inputs are validated against allowed ranges and the new configuration takes effect for subsequent evaluations immediately with an effective-from timestamp. Given an invalid configuration is submitted (e.g., N < 1, D < 0, min > max), When the API validates, Then the request is rejected with explicit error codes and messages and no partial changes are applied. Given any configuration change is accepted, When it is saved, Then an immutable audit log entry is created capturing actor, before/after values, reason, and timestamp, and is exportable. Given a rollback is requested to a prior configuration version, When the admin confirms, Then the selected version is restored and becomes active immediately with a new audit entry.
Transparent Cooldown Messaging
"As a borrower under cooldown, I want to understand why I’m limited and what I need to do to recover so that I can plan accordingly and improve my standing."
Description

Provide clear, context-aware messaging that explains current cooldown tier, what restrictions apply (e.g., narrowed windows, peak-hour blocks, trust requirements), and exactly how to restore access. Surface messages in search results, calendar tooltips, booking modals, and on the account status page; send email/push notifications when a tier changes. Include localized copy, accessible designs, and non-punitive tone. All messages must include reason codes and links to appeals or help articles.

Acceptance Criteria
Booking Modal Cooldown Banner
Given a logged-in user is under cooldown tier T with active restrictions R and restoration requirement K When the user opens the booking modal for any item Then a persistent cooldown banner is displayed above the date/time selector containing: (1) tier label/name and short description, (2) explicit list of active restrictions R, (3) machine-readable reason_code and human-readable reason text, (4) “Restore access” guidance showing remaining K on-time handoffs, and (5) visible links to Appeal and Help that deep-link to the account status page and help center And the banner renders within 200 ms after modal load and remains visible until booking completion or modal close And if the user is not under cooldown, the banner does not render And analytics event cooldown_banner_viewed with tier and reason_code is logged exactly once per modal open
Search Results Cooldown Indicator
Given a user is under cooldown tier T When the user views search results with item cards Then each item card displays a cooldown indicator/badge, and tapping/hovering reveals a tooltip summarizing current tier, key restriction(s), reason_code, and a link to “Learn more” that opens the account status page in the same locale And the indicator is hidden for users not under cooldown And the indicator does not overlap primary CTAs on common breakpoints (320–1440px) And the tooltip loads within 150 ms and is dismissed by ESC or blur
Calendar Tooltip Restrictions
Given a user’s cooldown restricts peak hours and/or narrows pickup windows When the user selects or hovers a time slot that is blocked by cooldown Then the slot is disabled and a tooltip explains the specific restriction, includes the current tier, reason_code, and a concise “how to restore” step, with a link to Appeal And eligible time slots remain selectable and show no cooldown tooltip And accessibility: the tooltip is keyboard-focusable, ESC to close, and has aria-describedby tied to the disabled slot
Tier Change Notification Delivery
Given a user’s cooldown tier changes from T1 to T2 When the tier change is persisted Then an email and a push notification (if opted-in) are sent within 5 minutes, each including: previous tier, new tier, activated restrictions, reason_code, restoration steps, and a deep link to the account status page And messages are localized to the user’s preferred language with English fallback if translation missing And duplicates for the same change are suppressed for 24 hours And deliveries are logged with delivery status and reason_code; failures are retried up to 3 times with exponential backoff
Account Status Page Cooldown Details
Given a user navigates to the Account Status page When the page loads Then the Cooldown section displays: current tier name and start date, all active restrictions with concise descriptions, the current reason_code(s) with human-readable explanations, a chronological log of no-shows/infractions leading to the current tier, and a progress meter showing X of Y on-time handoffs completed toward restoration And links to Appeal and Help are visible above the fold and functional And the data reflects the latest state within 10 seconds of any tier change And content is localized and uses non-punitive tone per copy guide (no instances of banned terms: “punish”, “penalty”, “suspend”)
Localization and Accessibility Compliance
Given any surface that renders cooldown messaging (search results, calendar tooltips, booking modal, account status, email, push) When the surface is presented in a supported locale (en, es, fr, de at launch) Then the message appears in that locale with all variables substituted; missing translations fall back to English with a telemetry flag translation_fallback=true And all UI messages meet WCAG 2.1 AA for contrast (>=4.5:1), keyboard operability, focus order, and include appropriate ARIA labels/roles; emails include semantic HTML and text alternatives And copy readability is <= Grade 8 (FKGL or equivalent)
Reason Codes and Appeal Links Consistency
Given a cooldown message renders on any surface When the message is displayed Then it includes a machine-readable reason_code (e.g., NS-2) that matches the user’s cooldown record and a brief human-readable reason And it provides two functional links: Appeal (to appeals flow) and Help (to the relevant article), both localized and returning HTTP 200 And telemetry events include reason_code and surface_id for every render And unit tests validate reason_code mapping coverage >= 99% of known codes
Calendar & Availability Enforcement
"As a borrower with restrictions, I want the calendar to only show times I’m allowed to book so that I can complete a reservation without confusion or errors."
Description

Integrate cooldown restrictions into Sharehood’s live calendar so ineligible slots are filtered out before selection. Automatically narrow offered pickup windows per tier, block community-defined peak hours, and re-check eligibility at confirm time. Ensure compatibility with smart pickup window auto-adjustments and conflict resolution, and maintain performance under peak load. Provide graceful fallbacks if policy evaluation is temporarily unavailable.

Acceptance Criteria
Pre-Selection Slot Filtering by Cooldown Tier
Given a borrower in a cooldown tier with defined slot restrictions, when the borrower opens an item's live calendar, then all time slots the borrower is ineligible for due to cooldown policies are not selectable and display an ineligibility message on hover/tap. Given an attempt to access an ineligible slot via direct URL or API, when the request is made, then the backend returns 403 with reason code cooldown_ineligible and the slot remains unbooked. Given the calendar loads, when eligibility filtering is applied, then the response includes only slots permitted by the borrower's current tier and trust level.
Auto-Narrowed Pickup Windows per Cooldown Tier
Given policy configuration defines per-tier pickup window durations (e.g., Tier 1=60m, Tier 2=30m, Tier 3=15m), when a borrower in Tier 2 views available pickup windows, then the offered windows are exactly 30 minutes and do not exceed the configured duration. Given smart window auto-adjustment would widen a window to resolve overlap, when the borrower is in a cooldown tier, then the widened window does not exceed the tier's configured maximum; if no compliant window exists, the slot is withheld. Given a booking is created, when the confirmation is generated, then the stored reservation reflects the correct narrowed window duration for the borrower's tier.
Peak-Hour Blocking Respecting Community Policy
Given community policy marks peak hours, when a borrower in a restricted tier views the calendar, then slots overlapping those hours are filtered out or disabled per policy. Given daylight saving or time zone differences, when peak hours are evaluated, then the block is applied using the item owner's location time zone. Given a borrower is upgraded to a tier without peak-hour restrictions, when they refresh the calendar, then previously blocked peak-hour slots become selectable if otherwise available.
Eligibility Re-Check at Confirmation with Race-Condition Handling
Given a borrower selects a slot and proceeds to confirmation, when the borrower clicks Confirm, then the system re-evaluates cooldown tier, trust, and peak-hour compliance and only creates the booking if all are currently eligible. Given the borrower becomes ineligible between selection and confirmation, when they click Confirm, then the booking is rejected with a non-200 response and an inline message explaining the rule that failed, and alternative eligible slots are returned. Given concurrent confirm attempts for the same slot, when one succeeds, then the second receives a 409 conflict and no duplicate reservations or holds are created.
Compatibility with Smart Auto-Adjust and Conflict Resolution
Given smart pickup window auto-adjust detects an overlap, when the borrower is in a cooldown tier, then any adjusted window remains within the tier's maximum duration and outside restricted peak hours. Given two pending requests overlap, when conflict resolution runs, then priority is not given to a cooldown borrower if it would force a non-cooldown borrower into a policy-violating window; the system proposes compliant alternates instead. Given both UI and API clients, when adjustments occur due to cooldown enforcement, then both surfaces return/display the same final enforced window times for the slot.
Performance and Graceful Fallback Under Policy Service Degradation
Given normal peak traffic (p95 200 concurrent viewers per item), when the calendar is requested with policy enforcement enabled, then the calendar API responds with p95 <= 500 ms and p99 <= 900 ms including eligibility filtering. Given the policy evaluation service times out (>2 s) or is unavailable, when the borrower opens the calendar, then browsing still loads within p95 <= 700 ms and displays an eligibility-check delayed banner; slots are tentatively visible but cannot be confirmed without a successful re-check. Given confirm is attempted while policy evaluation is unavailable, when the borrower clicks Confirm, then the system returns a retriable error with reason policy_unavailable, no reservation is created, and the user is prompted to retry once the service recovers.
Admin Policy Controls & Overrides
"As an organizer, I want to configure and override cooldown policies with audit trails so that the system fits our community’s norms and edge cases."
Description

Deliver an admin panel for organizers to configure cooldown thresholds, restriction types, decay rates, earn-back steps, and trust-level requirements. Allow per-community overrides, temporary exceptions (e.g., medical or emergency), and one-click user tier resets with mandatory audit logging. Include analytics to monitor flake rates, tier distribution, and impact on fulfillment, plus exportable reports for HOA/tenant boards.

Acceptance Criteria
Admin sets cooldown thresholds and restriction types
Given an organizer with Admin role for Community A When they open Flake Cooldown Policy settings and set No‑Show Threshold = 2 within 30 days And select Restriction Types = Narrowed pickup windows (30 minutes), Peak-hour restriction (5pm–8pm), Minimum Trust Level = 60 And click Save Then the policy is saved with a new version number and timestamp And a success message is displayed And the configured rules apply only to bookings created after the save time And the read-only policy view shows the current version, editor admin ID, and effective time
Configure decay rates and earn‑back steps
Given a community policy editor screen with Decay and Earn‑Back sections When the admin sets Strike Decay = 1 strike removed every 14 days without a no‑show And sets Earn‑Back = Restore full access after 3 consecutive on-time pickups within 45 days And saves the policy Then the system calculates and displays each affected member’s projected restore date And member-facing policy banners reflect the earn-back path and remaining steps And after a member records 3 on-time pickups within the window, restrictions are automatically lifted And an audit log entry records the lift with member ID, policy version, and triggering events
Per‑community override with precedence rules
Given global default cooldown policies exist And Community B has no overrides When the admin of Community B toggles "Override Global" and configures a stricter threshold (1 no‑show in 30 days) and narrower windows (20 minutes) Then members booking within Community B are evaluated against Community B’s override rather than globals And members belonging to multiple communities are evaluated using the policy of the community tied to the booking inventory And changing Community B’s policy does not retroactively alter restrictions on already confirmed bookings And the policy detail page displays "Precedence: Community Override > Global"
Temporary exception (medical/emergency) with expiry and audit
Given a member currently under cooldown restrictions When an admin grants a Temporary Exception with Reason = "Medical", Start = now, End = 7 days Then the member’s restrictions are suspended only for the exception window And the member’s booking flow shows an "Exception Active until <date>" notice And after the end date passes, the prior restrictions automatically reapply without admin action And an immutable audit record is created with member ID, admin ID, reason, start/end timestamps, and scope of exception And the system prevents saving an exception without a reason or with End > 14 days from Start
One‑click user tier reset with mandatory justification and logging
Given an admin is viewing a member profile under the Cooldown tab When the admin clicks "Reset Tier to Baseline" Then a modal requires a justification (minimum 15 characters) and displays before/after tier values And upon confirm, the member’s tier resets to baseline and active restrictions are cleared And the member is notified in-app and via email of the reset and the earn-back expectations And an audit entry captures admin ID, timestamp, prior tier, new tier, justification text, and policy version
Analytics dashboard: flake rates, tier distribution, and fulfillment impact
Given an admin opens Analytics > Cooldown Impact When they select Date Range = last 90 days and Community Filter = All Then the dashboard displays: overall flake rate (% no‑shows / bookings), flake rate trend by week, tier distribution counts, and fulfillment rate (%) And each metric has a definition tooltip and matches the underlying data when cross-checked against raw booking events And filters (community, member tier, time range) re-compute metrics within 2 seconds for datasets up to 100k bookings And data timestamps reflect the admin’s selected timezone
Exportable board reports with applied filters and reproducibility
Given an admin opens Reports and selects "Cooldown Impact Summary" When they choose Community = Community A, Date Range = Q2, and Format = CSV and click Export Then a downloadable file is generated within 30 seconds including: report title, community, date range, generation timestamp, and all active filters in the header And the report contains aggregated metrics (flake rate, tier distribution, fulfillment impact, top 5 policy changes) with values matching the Analytics view for the same filters And the export excludes personally identifiable information by default And the export action is recorded in the audit log with admin ID and a hash of the dataset for reproducibility

Chain Builder

Design your entire project timeline in one flow. Pick tasks, set a deadline, and Sharehood maps required items to live availability, auto-reserving sequential slots across multiple lenders. A visual timeline shows gaps and fit so you can lock a plan in minutes instead of juggling individual bookings.

Requirements

Task Templates & Item Mapping
"As a project planner, I want to select tasks from templates that auto-map to required items so that I can build my plan quickly without researching every tool I need."
Description

Provide a catalog of common DIY and household project tasks with configurable durations, dependencies, and required item categories, plus support for custom tasks. Each task maps to Sharehood’s inventory taxonomy to infer needed items, pickup/return behaviors, and default buffer times. The system stores template metadata (skill level, typical duration range, indoor/outdoor, recommended lead time) and versioning for organizer-curated templates. This enables Chain Builder to translate a user’s task list into concrete resource needs without manual item-by-item selection, improving speed and accuracy while remaining editable by the user.

Acceptance Criteria
Template Selection Maps Tasks and Metadata
Given a user opens Chain Builder and searches the task catalog When the user selects the template "Paint a Room" and clicks Add to Plan Then the system adds all template-defined tasks to the plan with their default durations and dependencies And each task is populated with its required item categories from the inventory taxonomy And the template metadata (skill level, typical duration range, indoor/outdoor, recommended lead time) is stored with the plan and is viewable on the task details panel And no manual item selection is required to proceed to the next step
Edit Durations, Dependencies, and Buffers
Given a plan that includes tasks from a template with default durations, dependencies, and buffers When the user edits a task duration and reorders a dependency Then the plan recalculates the dependent task start/end estimates immediately And default pickup/return buffers tied to the edited tasks adjust accordingly And if a circular dependency is introduced, the system prevents saving and shows a validation error specifying the offending tasks And upon successful save, the updated values persist and are reflected in subsequent resource need calculations
Taxonomy-Driven Item Inference and Buffer Injection
Given a task with required item categories mapped to the Sharehood inventory taxonomy When the system infers needed items for the plan Then it assigns pickup/return behaviors based on taxonomy rules for each category And it injects default pre-pickup and post-return buffer times per category into the schedule model And it deduplicates identical categories across adjacent tasks while preserving required time windows And it exposes the inferred categories and buffers on the task for user review and edit
Custom Task Creation with Category Mapping
Given a user needs a task not found in the catalog When the user creates a custom task providing a name, duration, and at least one required item category Then the system validates mandatory fields and confirms each category exists in the taxonomy And the task is saved with optional metadata (skill level, indoor/outdoor, typical duration range, recommended lead time) if provided And the custom task appears in the plan with inferred pickup/return behaviors and default buffers from the taxonomy And the custom task can be reused via search in the current session
Metadata Visibility and Lead-Time Guidance
Given a template task with recommended lead time of N days and indoor/outdoor and skill level metadata When a user sets a plan start date within fewer than N days Then the system displays a non-blocking warning that lead time is not met And the warning is visible on the task row and details panel And the metadata fields (skill level, duration range, indoor/outdoor, recommended lead time) are readable via UI and API for the task And proceeding without meeting lead time does not alter the inferred item categories or buffers
Organizer Template Versioning and Stability
Given an organizer publishes a new version of a task template When a user creates a new plan after publication Then the plan uses the latest template version by default And existing plans created with prior versions remain locked to their original version without automatic changes And users can view template version history and see which version a plan uses And an optional, explicit migrate action applies deltas to a copy of the plan while preserving the original
Resource Needs Spec Generation for Auto-Reservation
Given a plan with tasks (template or custom) containing mapped item categories, buffers, and pickup/return behaviors When the user confirms the task list Then the system generates a resource needs specification per task including category ID(s), earliest start, latest end, estimated duration, and buffer requirements And the spec merges identical category needs across dependent tasks where feasible And the spec is exposed to the auto-reservation engine via an internal API and is viewable in a developer log for debugging And no hard item instance is reserved at this step
Real-time Cross-Lender Availability Aggregation
"As a borrower, I want to see real availability across nearby lenders so that the plan I create actually fits what neighbors can provide."
Description

Aggregate live availability for items across multiple lenders into a unified availability graph that respects lender blackout times, maintenance blocks, smart pickup windows, travel buffers, and timezone differences. Implement a caching layer with freshness SLAs and soft-lock verification to minimize race conditions at confirmation time. Expose a query API for the sequencing engine to request feasible windows by item category, location radius, and duration, ensuring accurate, low-latency planning at neighborhood scale.

Acceptance Criteria
Unified Availability Aggregation Across Lenders
Given three lenders (A, B, C) each with items and defined blackout times, maintenance blocks, and open hours When the aggregation API is requested for availability for the next 14 days for those items Then the returned availability graph omits slots overlapping any lender blackout or maintenance block And no slot spans outside the lender's open hours And each slot includes fields: lender_id, item_id, start_at, end_at, tz, version And overlapping inventory reservations are not duplicated across lenders And P95 response time <= 300 ms for up to 50 lenders and 500 items And changes to a lender's calendar propagate to the graph within 5 seconds P95
Smart Pickup Windows and Travel Buffers Applied
Given a borrower location and a required 10-minute buffer between sequential bookings When feasible windows are computed for an item requiring pickup and drop-off Then each window includes a smart pickup window of at least 10 minutes within lender open hours And sequential reservations for the same borrower enforce a minimum 10-minute buffer between previous drop-off and next pickup start, adjusted for travel time if provided And no window is returned that crosses lender-closed hours And returned windows include fields: pickup_start, pickup_end, buffer_applied (boolean), buffer_minutes And P95 computation time <= 250 ms for 200 candidate slots
Timezone Normalization and DST Safety
Given lenders in multiple timezones and a requestor timezone of America/Los_Angeles When availability is returned spanning a DST transition Then all times are returned in ISO 8601 with explicit offset and tz database name And no slot overlaps or gaps are introduced due to DST; each slot preserves its real-world duration And cross-timezone aggregation aligns by UTC; ordering by start_at UTC is consistent And a 120-minute slot remains 120 minutes across DST boundaries in both local and UTC representations And unit tests cover at least 4 DST transition cases across different regions
Caching Freshness and SLA
Given the caching layer is enabled with TTL=15s and stale-while-revalidate=60s When identical queries repeat within TTL Then responses are served from cache with header X-Cache=HIT and P95 latency <= 120 ms And after TTL expiry, the first request may serve stale data only while revalidation is in-flight and marks X-Cache=STALE; freshness_age_seconds <= 60 And any lender calendar update invalidates related cache keys within 2 seconds P95 And cache is namespaced by neighborhood and category; no cross-tenant data leakage is observed in test And cache keys include all request parameters; load test at 100 QPS yields cache HIT ratio >= 0.7
Soft-Lock Verification at Confirmation
Given a client submits a booking confirmation for a slot from the availability graph When the soft-lock verification endpoint is called with an idempotency_key Then the lock is granted only if the slot is unclaimed and the version matches And on success the slot is soft-locked for 90 seconds and a lock_id is returned And on conflict the API returns 409 with at least 3 alternative slots when available And repeated calls with the same idempotency_key are idempotent (no duplicate locks) And P95 verification latency <= 150 ms and soft-lock false-positive rate <= 0.1%
Query API: Feasible Windows by Category, Radius, and Duration
Given a request filtering by category=power-tools, radius_km=5, duration=3h, and borrower geolocation When calling GET /v1/availability/windows with valid parameters Then the API returns HTTP 200 with a list of windows sorted by soonest_start And each window includes: item_id, lender_id, start_at, end_at, distance_km, price_estimate, pickup_window, tz And results are limited to lenders within 5 km geodesic radius using Haversine with precision <= 50 m And pagination via cursor is supported with default page_size=25 and next_cursor when more results exist And invalid parameters return 400 with field-specific error messages; unsupported category with no matches returns HTTP 200 and an empty list And P95 latency <= 250 ms for neighborhoods within 10 km radius and up to 2,000 indexed items
Sequential Auto-Reservation Engine
"As a time-constrained user, I want the system to auto-reserve the items I need in sequence so that I can lock my project plan without juggling individual bookings."
Description

Compute sequential schedules that satisfy task order, item requirements, user deadline, and buffer constraints, then place provisional holds across multiple lenders. Optimize for feasibility and convenience by inserting smart pickup/return windows, minimizing travel with location weighting, and preferring single-lender continuity when possible. Support hard deadlines, flexible windows, and alternative item substitutions when the preferred plan is infeasible. On confirmation, convert holds into bookings and initiate Stripe deposit authorizations; on partial failure, rollback and offer actionable suggestions.

Acceptance Criteria
Sequential Schedule Meets Task Order, Buffers, and Deadline
Given a chain with ordered tasks, required items, task durations, buffer minutes between tasks, and a hard completion deadline And lender calendars expose available slots and pickup/return hours When the engine computes a schedule Then each task is assigned to an item slot that starts after the previous task’s end plus the configured buffer And no assigned slot overlaps another assigned slot for the same user And the final task end time is on or before the hard deadline And only calendar slots marked available are used And pickup/return windows are auto-adjusted to avoid overlaps while preserving buffers and lender pickup hours
Atomic Provisional Holds Across Multiple Lenders with Expiration
Given a feasible schedule with N item slots across M lenders When the engine places provisional holds Then a hold is created for each slot with a shared chain_id and unique hold_id per slot And holds are visible to lenders as blocking and prevent other bookings for the held interval And if any hold fails, all previously placed holds for the chain are released within 1 second And each hold has an expiration timestamp (TTL) configured, default 15 minutes, surfaced to the user And retrying the same request with the same correlation_id is idempotent and does not duplicate holds
Plan Selection Prioritizes Single-Lender Continuity and Minimizes Travel
Given multiple feasible schedules exist for the same chain When the engine selects the plan to present Then it chooses a schedule with the fewest distinct lenders And among ties, it chooses the schedule with the lowest total travel distance computed via Haversine between consecutive pickup/return/user-home coordinates And among remaining ties, it chooses the schedule with the earliest final completion time And pickup/return windows are clustered to minimize back-to-back travel where lender hours permit
Flexible Time Windows and Hard Deadline Compliance
Given tasks with earliest_start and latest_end windows and an optional hard deadline When the engine computes a schedule with flexibility enabled Then each task’s start time lies within its specified window And the final completion time is on or before the hard deadline when provided And the response returns concrete start/end times per task and the shift (in minutes) applied within each window And if no schedule fits, the engine marks the chain infeasible and identifies the first violated constraint (window, buffer, item availability, or deadline)
Alternative Item Substitution When Preferred Plan Is Infeasible
Given a task requires a preferred item with capability tags and defined substitution rules And the preferred item is unavailable for the needed interval When substitutions are allowed Then the engine proposes a schedule using substitute items that satisfy all required capability tags and user constraints (e.g., price cap, max extra pickups) And substitution choices are ranked to minimize added pickups and travel distance And the response explicitly lists each substitution and the rationale And if only substitutions violating user constraints are possible, the plan is marked infeasible with suggested constraint adjustments
Confirmation Converts Holds to Bookings and Triggers Stripe Deposits
Given an active set of provisional holds for a chain When the user confirms the plan Then each hold is atomically converted into a booking with a booking_id and lender notifications are sent And Stripe deposit authorizations are created per booking using configured deposit amounts and idempotency keys And the overall operation is all-or-nothing; on success no holds remain, on failure no bookings persist And repeating confirmation with the same idempotency key does not create duplicate bookings or charges
Partial Failure Rollback with Actionable Suggestions
Given a failure occurs during hold placement, booking conversion, or payment authorization When the engine handles the error Then all holds and bookings created in the transaction are rolled back and calendar availability is restored within 2 seconds And the user is presented at least three actionable suggestions (e.g., shift start by ≤30 minutes, relax buffer by ≤10 minutes, choose substitute item, extend deadline) ranked by feasibility And each suggestion states the violated constraint and expected impact on travel and completion time And no orphaned holds remain (verified by availability recheck) and an audit log entry is recorded
Visual Timeline & Gap Resolution
"As a visual planner, I want to see and adjust my project timeline so that I can resolve gaps and confirm a plan that fits my schedule."
Description

Provide an interactive timeline that displays tasks, assigned items, buffers, and lender sources, with drag-and-drop adjustments to task order and duration. Highlight conflicts and gaps with inline guidance and one-click fixes such as shifting slots, swapping items, or adjusting pickup windows. Include day/hour zoom, mobile responsiveness, color-coding by lender, and accessible interactions. Persist timeline edits back to the sequencing engine to re-evaluate feasibility in real time.

Acceptance Criteria
Interactive Timeline Rendering and Zoom
Given a chain with tasks, assigned items, buffers, and lender sources, when the timeline loads, then each task and buffer is displayed in chronological order with a distinct color per lender and labels for task name, item, lender, and start/end times. Given color-coding by lender is applied, when multiple items from the same lender appear, then they consistently share the same color and conflicts are not indicated by color alone. Given day zoom is active, when the user switches to hour zoom, then the time scale updates to hour granularity, the viewport remains centered on the currently focused task, and task positions/lengths reflect exact start/end times without visual overlap truncation. Given hour zoom is active, when the user switches to day zoom, then tasks aggregate to the day grid while preserving relative ordering and tooltips or focus details reveal precise times. Given the timeline has more than 20 tasks, when the user pans horizontally, then interactions remain responsive with input latency under 100 ms and no frame hitch lasting longer than 200 ms.
Drag-and-Drop Reorder and Duration Adjustments
Given the timeline is loaded, when the user drags a task to a new position in the sequence, then the task moves to the new slot, dependent tasks shift accordingly, and provisional start/end times update immediately in the UI. Given the user drags the start or end handle of a task, when the handle is released, then the task duration snaps to the nearest available slot boundary for the assigned item and buffers are preserved. Given a new position or duration violates item availability or buffers, when the drag completes, then the system prevents commit and displays a non-blocking conflict indicator with inline guidance. Given keyboard-only operation, when a focused task is picked up with Space and moved with Arrow keys in 15-minute increments, then the task repositions with the same validation rules and an aria-live announcement states the new start and end times. Given an edit has been made, when the user triggers Undo, then the last change reverts and both the timeline view and provisional holds revert to the prior state.
Conflict Detection and Inline Guidance
Given an item overlap, unavailable slot, or out-of-window pickup exists, when the timeline renders or is edited, then each affected segment is highlighted, a badge shows the total conflict count, and an inline guidance panel appears with recommended fixes. Given the user expands a conflict entry, when details are shown, then the panel lists task, item, lender, start/end time, conflict type, and severity. Given a conflict is resolved by any edit or fix, when feasibility recomputation completes, then the conflict highlight and count badge update within 1 second and the guidance panel reflects the new status. Given multiple conflicts exist, when the user filters by conflict type, then only matching conflicts remain visible in the list and on the timeline.
One-Click Gap Resolution Actions
Given a conflict caused by overlapping reservations, when the user selects Shift Slots, then the system proposes the minimal time shift to resolve all current overlaps without violating buffers; upon confirm, the timeline and reservations update accordingly. Given a conflict caused by item unavailability, when the user selects Swap Item, then a list of compatible items with available slots across lenders is shown sorted by best fit; upon selection, the task, color-coding, and reservations update. Given a conflict that can be fixed by pickup timing, when the user selects Adjust Pickup Window, then the pickup is moved within the configured tolerance (e.g., ±30 minutes) and feasibility is reevaluated. Given any one-click fix is applied, when the operation succeeds, then a success notification appears and no new conflicts are introduced; when it fails or exceeds 2 seconds, then an error with retry is shown and no partial or orphan holds remain.
Persistence to Sequencing Engine with Real-Time Re-evaluation
Given the user commits a timeline edit or applies a fix, when the change is sent to the sequencing engine, then an updated feasibility and reservation plan is returned within 2 seconds. Given a successful persistence response, when it is received, then reservation holds are updated to match the returned plan and the UI reflects final times and lenders without requiring a manual refresh. Given a persistence error or timeout occurs, when the response is handled, then the optimistic UI change rolls back, a descriptive error is displayed, and no stale or orphan holds remain on any lender. Given the chain is reopened after saving, when the timeline loads, then all previously saved edits appear and match the last successful plan from the sequencing engine.
Mobile Responsiveness and Accessibility Compliance
Given a mobile viewport of 375x667, when the timeline renders, then it fits the width, supports horizontal pan and pinch-to-zoom between day and hour scales, and labels remain readable without horizontal text clipping. Given a touch device, when the user long-presses a task and drags, then the task can be repositioned or resized using touch with the same validation and snapping rules as desktop. Given mobile controls, when actions are presented, then primary touch targets (Fix, Zoom, Undo) are at least 44 px and reachable within one tap from the timeline. Given lender color-coding and conflict states are displayed, when viewed by users with color vision deficiencies, then information is also conveyed by icons/text and meets WCAG 2.1 AA contrast requirements. Given keyboard-only and screen reader use on desktop, when interacting with tasks and conflict updates, then tasks are reachable via Tab order, have roles/labels including task, item, lender, and times, and conflict changes are announced via aria-live politely.
Stripe Deposit Orchestration for Chains
"As a borrower, I want a single, clear deposit hold for my whole plan so that I understand costs and avoid multiple charges across lenders."
Description

Manage deposit holds at the chain level with per-item breakdowns using Stripe. Create a consolidated authorization reflecting the maximum concurrent exposure, schedule staggered capture windows aligned to pickups, and auto-release upon verified returns. Handle partial cancellations and substitutions without double-charging, ensure idempotency, and present clear fee and hold summaries before confirmation. Integrate with Sharehood’s no-show policies to reduce risk for lenders while keeping borrower experience transparent.

Acceptance Criteria
Max Concurrent Exposure Authorization
Given a chain contains multiple items with defined deposit amounts and timeboxed pickups/returns When the borrower confirms the chain Then the system creates exactly one Stripe authorization whose amount equals the maximum concurrent sum of item deposit exposures across the chain timeline, not the sum of all items And the authorization amount is in the chain currency and rounded to the smallest currency unit And a per-item deposit breakdown with item IDs and active time ranges is stored in Stripe metadata and internal records And if the chain timeline changes before any pickup, the authorization is increased/decreased to match the new max concurrent sum without creating additional authorizations And at no time does the borrower’s total held amount exceed the computed max concurrent total
Staggered Capture Windows by Pickup
Given each item in the chain has a scheduled pickup window and a deposit portion under the consolidated authorization When a pickup window opens Then a capture eligibility window is scheduled per policy for that item and no capture occurs unless a no-show is detected And if pickup is verified within the window (or grace period), no capture is executed for that item And if a no-show is determined at window close, the system marks the item as no-show and flags the policy-defined capture amount for execution And if the pickup is rescheduled before window close, capture eligibility windows are updated to the new schedule without duplicating capture tasks
Auto-Release on Verified Return
Given an item is successfully picked up under the chain authorization When its return is verified by lender check-in or system validation Then the system issues a partial release to reduce the authorization by that item’s reserved portion within 2 minutes and updates the per-item breakdown And when all items are returned or canceled, the remaining authorization is fully released and the PaymentIntent is closed And if a partial capture was taken (e.g., damage/no-show fee), only the unused remainder of the authorization is released
Partial Cancellation and Substitution Adjustments
Given a chain has an active consolidated authorization When an item is canceled before its pickup window begins Then the authorization is decreased by that item’s deposit portion within 2 minutes and no charge is captured And the borrower UI reflects the updated hold total immediately after the adjustment When an item is substituted before pickup with another item having a different deposit requirement Then the authorization amount is adjusted by the delta only, and no second authorization is created And the system prevents any temporary double-hold condition during the adjustment
Idempotency and Concurrency Safety
Given network retries or duplicate client submissions during authorization, update, capture, or release When Stripe API requests are made Then each request includes an idempotency key derived from chainId + operation + version so that retries do not create additional charges or holds And concurrent update attempts result in a single consolidated authorization consistent with the latest persisted chain version And audit logs record idempotency keys, Stripe object IDs, before/after authorization amounts, and outcomes for each operation
Pre-Confirmation Fee and Hold Summary
Given a borrower reviews the chain prior to confirmation When the confirmation screen is displayed Then the UI shows a clear summary including per-item deposit amounts, max concurrent deposit total, currency, no-show capture rules, and release conditions And the displayed max concurrent total equals the authorization amount created upon confirmation to the cent And the Confirm action remains disabled until the borrower explicitly acknowledges the deposit and policy summary
No-Show Policy Capture Enforcement
Given an item’s pickup window closes without a successful pickup and the policy defines a no-show capture amount When the no-show condition is detected Then the system captures the policy-defined amount (not exceeding the item’s deposit or remaining authorized funds) within 15 minutes and sends receipts/notifications to borrower and lender And the remaining authorization is reduced by the captured amount and remains active for other items in the chain And if a late pickup occurs after the grace period, no additional no-show capture is attempted for the same window
Conflict Detection & Re-optimization
"As a borrower, I want the system to alert me and fix my plan if something changes so that my project can still finish on time."
Description

Continuously monitor for upstream calendar changes, lender responses, or user edits that invalidate any segment of a confirmed or held chain. Detect conflicts early and propose re-optimized alternatives that honor user-locked tasks and deadlines. Provide one-click apply, side-by-side comparison, and audit logging of changes. Notify affected lenders and borrowers and manage cascading updates to deposits and reminders to maintain trust and reliability.

Acceptance Criteria
Upstream Calendar Change Triggers Conflict Detection
Given a confirmed or held chain with future reservations and an upstream calendar event from a lender modifies or removes a reserved slot When the change webhook is received or a poll detects the change Then the chain is marked "Conflicted" and the impacted segment IDs are identified within 60 seconds And a re-optimization job is enqueued exactly once with the chain ID and conflict reasons And the borrower receives an in-app banner and email notification within 60 seconds indicating a conflict was detected and re-optimization is in progress
Automated Re-optimization Proposes Feasible Alternatives
Given a conflicted chain with known dependencies, item requirements, user-locked segments, and an overall completion deadline When re-optimization runs Then at least one proposal is generated that satisfies all locks and the deadline if a feasible plan exists And proposals reuse all unaffected segments and adjust only conflicted segments And up to 3 proposals are returned, ranked by least disruption and lower total cost And each proposal includes per-segment item, lender, start/end times, pickup/drop windows, cost and deposit deltas, and rationale for any change And if no feasible plan exists, the system returns "No feasible alternative" with explicit blocking constraints listed
Locked Tasks and Deadline Are Honored
Given the borrower has locked one or more tasks/segments and set a project deadline When re-optimization evaluates alternatives Then locked segments remain unchanged in all proposals And proposals that would violate the deadline are excluded And if honoring all locks makes the deadline impossible, the system surfaces an "Extend or Unlock" flow listing which locks cause infeasibility and the minimum extension required
One-Click Apply Updates Reservations and Financials Atomically
Given a selected proposal for a conflicted chain When the borrower clicks Apply Then the system performs an atomic transaction that creates/updates/cancels reservations to match the proposal and recalculates reminders And deposit holds are adjusted idempotently: new holds are placed successfully before old holds are released; if any new hold fails, all changes are rolled back And lenders removed from the chain receive cancellation notices; newly added lenders receive booking requests/holds And a success response is returned within 15 seconds for chains up to 10 segments, with a summary of changes And all ICS/iCal events are updated to reflect new times and locations
Side-by-Side Comparison and Change Highlighting
Given a chain with a generated proposal When the borrower opens the comparison view Then the UI presents original vs proposed timelines side-by-side with per-segment diffs (start/end, lender, item), total cost delta, and total deposit delta And all changed segments are visually highlighted; unchanged segments are labeled "Unchanged" And the borrower can filter to only show changed segments and export the proposal as PDF And accessibility checks pass for the comparison view (keyboard navigable and screen-reader labels present for all diff elements)
Audit Logging of Proposal Lifecycle
Given proposals are generated, viewed, applied, or dismissed When any of these events occur Then an immutable audit log entry is written with chain ID, actor (system or user), timestamp (UTC), event type, before/after values for each changed segment, and outcome status And audit entries are retrievable via admin API and internal UI within 2 seconds of the event And tamper detection is enabled via hash of payload and previous entry ID (append-only)
Notification and Reminder Cascade on Apply
Given a proposal has been applied When the transaction commits Then the borrower receives confirmation via in-app and email within 60 seconds, including updated timeline and cost/deposit summary And each affected lender receives an in-app/email notification within 2 minutes reflecting their new booking time or cancellation, with updated ICS attachments And prior reminders for superseded segments are cancelled and new reminders are scheduled according to policy And message templates include the reason for change (e.g., lender cancellation, user edit, upstream block)
Notifications, Approvals & Shareable Plans
"As an organizer, I want a shareable plan with automated notifications and lender approvals so that everyone stays aligned on pickups, returns, and any changes."
Description

Coordinate end-to-end communications for multi-lender chains, sending lenders consolidated requests with context (task, timing, buffers) and capturing approvals or alternatives. Notify borrowers of approvals, changes, pickups, and returns via preferred channels, and generate a shareable plan link for households or HOA organizers. Include reminder schedules, quiet hours, and a preferences center to reduce noise and improve adherence to the timeline.

Acceptance Criteria
Consolidated Lender Request with Context
Given a borrower finalizes a chain containing one or more items from the same lender When the borrower submits the chain for approval Then the system sends exactly one consolidated request per lender containing for each item: item name and ID, task name, pickup window start/end (ISO 8601 with timezone), return window start/end, buffer durations, pickup/return location, and special notes And the request also includes: borrower name, chain deadline, unique request ID, and cancellation policy And the request is delivered to the lender's preferred channel(s) within 15 seconds of submission And if the primary channel fails, a fallback channel is attempted within 60 seconds and logged And duplicate requests are not sent for the same unique request ID And the lender can open the consolidated request in-app with Approve/Decline/Propose Alternative actions at both per-item and bulk levels
Lender Approval, Decline, or Alternative Proposal
Given a lender opens a consolidated request When the lender selects Approve All, Approve Some, Decline, or Propose Alternatives Then the system records per-item status, timestamp, and actor ID And proposed alternative time windows must fit the item’s availability and maintain configured buffers; invalid proposals are blocked with an explicit validation message And upon Approve, items are tentatively reserved for 24 hours pending borrower confirmation; upon Decline, the item is released; upon Alternative Proposal, the borrower is prompted to accept or counter And if no lender response is received within 24 hours, the request auto-expires and the borrower is notified And all actions are written to the chain activity log and are filterable by actor and item
Borrower Notifications of Approvals and Changes
Given a chain has pending lender responses When any lender approves, declines, or proposes alternatives Then the borrower receives a notification via their preferred channel(s) within 15 seconds that includes affected items, new status, required next action, and a deep link to review And if all items reach Approved, the borrower receives a consolidated confirmation with pickup/return windows and an action to lock the plan And notification delivery failures are retried up to 3 times with exponential backoff and are logged with final status And duplicate notifications for the same event ID are suppressed
Pickup and Return Reminders
Given a chain has approved items with scheduled pickup and return windows When reminder offsets are configured to 24 hours and 2 hours before pickup and 30 minutes before return Then reminders are sent at the configured offsets using the plan’s time zone And each reminder includes item, location, window start/end, and a Confirm/Need Help action And if a reminder time falls within quiet hours, it is rescheduled to the earliest allowed time outside quiet hours while maintaining at least a 30-minute lead time And if a window changes within 2 hours of start, an urgent change alert is sent unless the user opted out of urgent alerts And all reminder sends and reschedules are recorded in the activity log
Quiet Hours Enforcement
Given a user has quiet hours set (e.g., 21:00–08:00 local time) and channel preferences configured When any non-urgent notification is scheduled during quiet hours Then it is suppressed and rescheduled to the next available time outside quiet hours And urgent notifications are only sent during quiet hours if the user has explicitly enabled Allow urgent during quiet hours And the rescheduled time includes the original scheduled time and reason in the audit log And no more than one rescheduled notification is sent within any 10-minute window per event
Notification Preferences Center
Given a user opens the Preferences Center When they update channel preferences per event type (approvals, changes, reminders, pickups, returns) and provide consent for SMS Then changes persist within 1 minute and apply to subsequent notifications And SMS cannot be enabled without recorded explicit consent and valid E.164 phone format And using Unsubscribe in email or replying STOP to SMS immediately opts the user out of that channel and reflects in the Preferences Center within 1 minute And a Test Notification action sends a confirmation within 15 seconds to the selected channel and records delivery status
Shareable Plan Link for Households/Organizers
Given a borrower locks a plan When they generate a shareable plan link Then a unique, read-only URL is created with optional access code protection that expires 7 days after the final return window And the shared view displays task sequence, items, lenders’ display names only (no private contact info), pickup/return windows, buffers, and borrower responsibilities And any plan change updates the shared view within 10 seconds And the borrower can revoke the link at any time, after which the URL returns 404 within 10 seconds And link access events (view, revoke, expiry) are logged with timestamp and viewer fingerprint where available

Swap Assist

When an item is unavailable or too far, get instant, compatible alternates with clear tradeoffs in time and cost. One-tap swaps keep your chain intact—no rebuilding—so projects stay on schedule even as inventory shifts.

Requirements

Compatibility Matching Engine
"As a borrower planning a project, I want compatible alternates suggested when my chosen item is unavailable or too far so that I can keep my project on schedule without manual research."
Description

Identify and rank compatible alternate items when a selected item is unavailable or exceeds a user’s distance threshold. Uses Sharehood’s item taxonomy and attributes (capabilities, power source, size, required accessories) plus project context to ensure fitness-for-purpose. Computes a compatibility score and filters by real-time availability, owner policies, and HOA rules. Integrates with the live calendar to verify pickup/return windows and prevents conflicts. Returns a curated shortlist ready for instant swap.

Acceptance Criteria
Unavailable or Too-Distant Item Triggers Curated Alternates
Given a user-selected item is unavailable for the requested window or exceeds the user’s distance/travel-time threshold And the user invokes Swap Assist When the Compatibility Matching Engine runs Then it returns a shortlist of 3–5 alternates And results are sorted descending by compatibility_score And 100% of results meet mandatory capability and project context constraints And each result displays name, compatibility_score (0–100), distance/travel time, pickup/return windows, required accessories availability, and total estimated cost And the shortlist is generated within 1500 ms at p95 And if no results qualify, a single “No compatible alternates” state is shown with at least one actionable suggestion (e.g., adjust window or distance)
Deterministic Compatibility Scoring and Exclusion Rules
Given a candidate item and project context (required capabilities, power source, size, accessories) When computing the compatibility_score Then any item failing a mandatory capability is excluded (not scored) And the score is deterministic and computed as a weighted sum with default weights: capability match 0.50, power source alignment 0.20, size fit 0.10, accessory readiness 0.10, travel time 0.05, policy alignment 0.05 And the score is normalized to a 0–100 scale with two-decimal precision And a “View details” action reveals the factor breakdown for the selected result And changing any input attribute recomputes the score and updates the UI within 200 ms after API response
Live Calendar Alignment and Conflict Prevention
Given the user’s planned pickup and return window And live calendar data for each candidate item When generating the shortlist Then only candidates with non-conflicting availability for the required duration are included And overlapping reservations are prevented by applying a 60-second soft lock on candidate time slots while the shortlist is displayed And if exact windows don’t fit, candidates with auto-adjusted windows within ±30 minutes are included and labeled “Adjusted” And selecting an adjusted option updates the booking times without creating calendar conflicts
Owner Policies and HOA Rule Compliance Filtering
Given applicable HOA rules and owner policies (e.g., pickup methods, deposit requirements, usage restrictions) are loaded When filtering candidate items Then any item violating an applicable rule or policy is excluded from the shortlist And each included result displays badges for applied policies (e.g., Deposit Required, Indoor Use Only) And if all candidates are excluded due to policies, the user sees “No compatible alternates” with reason “Policy constraints” and a link to view rules And policy evaluation decisions and reasons are logged for audit with item and policy identifiers
Distance and Travel-Time Threshold Enforcement
Given the user has set a distance or travel-time threshold (default 2 miles or 15 minutes) When generating the shortlist Then only items whose pickup location meets the threshold under current routing conditions are included And threshold units can be miles or minutes, with conversions based on live routing estimates And if zero items meet the threshold, the UI prompts to expand the threshold by +25% and supports one-tap retry And displayed travel time for each result matches the routing provider estimate within ±2 minutes
Instant Swap Applies Without Breaking Booking Chain
Given the user selects an alternate from the shortlist When confirming the swap Then the original booking is updated in place (project chain, timeline, and chat thread remain intact) And deposit hold and payment terms transfer atomically to the new item And both involved owners receive notifications within 10 seconds of confirmation And the original item’s inventory is released only after successful swap; on any failure, all changes are rolled back and the original booking remains active And an audit log entry is recorded with a correlation ID for the swap transaction
Performance, Fallbacks, and Error Handling
Given steady-state load up to 50 shortlist requests per second When the engine is invoked Then the API responds within 1500 ms at p95 and 3000 ms at p99 with valid results or an explicit error state And circuit breakers isolate failures from calendar and policy services And if a dependency is degraded or unavailable, the engine returns a non-stale error state (no alternates) with a retry affordance rather than outdated suggestions And success/failure counts and latency are emitted to monitoring with trace IDs for each request
Time & Cost Tradeoff Scoring
"As a borrower, I want to see clear time and cost differences among alternates so that I can choose the best option for my constraints."
Description

For each alternate, calculate and display clear tradeoffs across travel time/distance, pickup window adjustments, pricing deltas (hourly/daily), deposit amounts, and lender reliability. Labels options (e.g., Fastest, Cheapest, Closest) and shows deltas versus the current booking. Uses mapping/travel-time APIs and integrates with smart pickup windows to ensure feasibility. Presents top options with a consistent, mobile-first card layout for rapid decision-making.

Acceptance Criteria
Tradeoff Metrics Computation and Display
Given an unavailable or distant item and at least 3 compatible alternates are found via APIs When the user opens Swap Assist results Then each alternate card shows travel time (minutes), distance (mi/km per locale), pickup window shift (start/end adjustment), hourly price, daily price, deposit amount, and lender reliability score Given the system has fetched travel data When cards render Then travel times and distances are computed using the configured mapping API within the last 5 minutes and show an updated timestamp no older than 5 minutes Given numeric values are displayed When viewed across alternates Then units and formats are consistent (localized currency, time rounded to nearest minute, distance to one decimal) Given an alternate lacks a metric When rendering Then the metric displays "—" with a tooltip "Not provided" and the card remains selectable
Option Badging: Fastest, Cheapest, Closest
Given a result set of 3 or more alternates When results load Then exactly one Fastest badge is applied to the lowest travel time, one Cheapest badge to the lowest total cost for the selected duration, and one Closest badge to the shortest distance Given ties for a badge When two or more alternates are equal on the primary metric Then the badge is assigned to the alternate with the higher reliability score; if still tied, to the lower deposit; if still tied, to the earliest pickup availability Given fewer than 3 alternates When results load Then badges are applied where computable and no placeholder badges are shown Given filters or location change When the list updates Then badges recalculate and update within 500 ms of render
Delta Comparison Against Current Booking
Given the user has a current selection When alternates are displayed Then each metric shows a delta versus the current selection with sign and units (e.g., +12 min, -$3.50/day, +0.8 mi) Given a metric equals the current selection When deltas are computed Then the delta displays 0 with neutral formatting Given currency values When price deltas are shown Then they are rounded to two decimals and include the localized currency symbol Given the user changes duration or pickup window When the list updates Then deltas recompute and render within 500 ms
Smart Pickup Window Feasibility Gate
Given smart pickup windows for the user's booking chain When computing alternates Then only alternates whose pickup and return windows can be adjusted without overlap or violation are included in results Given an alternate is excluded by feasibility rules When the user taps Why not? Then a reason is shown with the conflicting window(s) (e.g., Return overlaps another booking) Given a feasible alternate is selected When the user proceeds Then updated pickup and return times are applied and shown on the confirmation screen Given API latency during feasibility checks When windows are recomputed Then results show a loading state within 300 ms and do not display stale feasibility indicators
Lender Reliability Metric and Explanation
Given lender performance data exists When rendering alternates Then each card displays a reliability score on a 0–5 scale with one decimal and a New lender label if fewer than 5 completed loans exist Given the user taps the reliability info icon When the details are shown Then the breakdown includes acceptance rate, on-time rate, cancellation rate, and sample size for the last 90 days Given no reliability data exists When rendering Then the card displays No data yet for reliability and remains selectable
Mobile-First Alternate Card Layout and Performance
Given a device width between 320 and 414 px When results are displayed Then each alternate renders as a single-column card with content order: title, badges, time/distance, pickup window shift, hourly/daily prices with deltas, deposit with delta, reliability, and primary Swap CTA Given a touch device When interacting with cards Then all tap targets are at least 44 px in height and text meets minimum contrast for readability Given a typical 4G connection When the results screen opens after API response Then the first three cards render within 1.0 s and images lazy-load without causing layout shift Given dynamic updates (filters, location, duration) When cards re-render Then scroll position is preserved and no vertical jump occurs
API Data Freshness and Error Handling
Given mapping and travel-time APIs are queried When an API fails or exceeds 2 s Then the system retries once and falls back to distance-only scoring with a banner Live travel time unavailable while continuing to display results Given pricing and deposit data are queried When prices or deposits cannot be fetched Then the card displays Pricing unavailable and disables the Swap CTA for that card Given cached travel or pricing data is older than 10 minutes When results would be rendered Then a refresh is triggered before display and the updated timestamp reflects the current fetch time
One-Tap Swap Workflow
"As a borrower with a multi-item project, I want to swap one item with a single tap so that I don’t have to rebuild my reservations."
Description

Replace the reserved item with a selected alternate in a single action without rebuilding the booking chain. Updates reservation records, live calendar slots, pickup/return windows, locations, and reminders; revalidates conflicts and re-applies smart window adjustments. Preserves project identifiers and linked items, supports undo within a short grace period, and handles both web and mobile flows. Ensures atomicity so swaps either fully succeed or safely roll back.

Acceptance Criteria
One-Tap Swap Without Chain Rebuild
Given a confirmed reservation R in project P with chain_id C and primary item A And an alternate item B is pre-selected in the Swap Assist panel When the user confirms Swap with a single tap/click Then reservation R is updated in place to use item B in a single server transaction And project_id P and chain_id C remain unchanged And no new booking chain is created and no multi-step rebooking flow is initiated And the number of user actions required to complete the swap is exactly 1
Conflict Revalidation Blocks Incompatible or Unavailable Alternates
Given alternate item B is incompatible with the reservation requirements or results in an unrecoverable conflict after smart window recalculation When the user attempts the one-tap Swap Then the swap is not committed And reservation R remains on item A with all details unchanged And the user receives a clear error stating the reason and suggesting next available times or compatible items And no calendar, reminder, or location updates are performed
Calendar, Smart Windows, Locations, and Reminders Updated
Given alternate item B has availability window Wb and pickup location Lb When the swap succeeds Then the live calendar frees A’s time blocks for reservation R and blocks B’s time blocks per Wb And pickup and return windows on R are recalculated using the configured smart-window rules and saved And pickup/return location on R updates to Lb And existing reminders are canceled and regenerated to reflect the new windows and location for the borrower and organizer
Atomic Transaction and Safe Rollback
Given a network, validation, or persistence error occurs during any step of the swap When the swap is executed Then either all updates across reservation, calendar, windows, location, and reminders are committed together or none are committed And if any step fails, the system rolls back to the exact pre-swap state with no partial changes And the user is informed of the failure and a traceable error ID is logged
Preservation of Project and Linked Items
Given reservation R has project_id P and linked accessory items [X, Y] When the swap succeeds to alternate item B Then project_id P remains unchanged And linked items [X, Y] remain associated with R And compatibility with linked items is revalidated; if incompatible, the swap is blocked and the user is informed which links conflict
Undo Within Grace Period
Given swap S completed less than 5 minutes ago And the original item A remains available for the original windows When the user taps Undo Swap Then reservation R is restored to item A with original windows, location, and reminders And an audit entry records the undo event If A is no longer available, Then Undo is prevented and the user is informed that availability has changed and the swap remains in place
Cross-Platform Swap Parity (Web and Mobile)
Given the user performs a one-tap swap on web or mobile When the operation completes Then the resulting reservation data, calendar state, windows, location, and reminders are identical across platforms within 2 seconds of sync And the number of user actions required is one on each platform And success and error messages convey the same meanings and codes across platforms
Payment & Deposit Reconciliation
"As a borrower, I want payments and deposits to adjust automatically when I swap so that I’m charged correctly without extra steps."
Description

Automatically reconcile pricing and deposit changes during a swap. Calculates pro-rated charges/refunds, updates Stripe PaymentIntents, and transfers/adjusts deposit holds from the original lender to the new lender without releasing the overall hold prematurely. Supports additional authentication if the deposit increases, applies platform fees correctly, and rolls back the swap on payment failure to maintain data integrity. Provides transparent receipts and in-app confirmations.

Acceptance Criteria
Pro-Rated Charge/Refund Calculation on Swap
Given an active booking with a defined start/end time and a completed lender handoff And a swap is initiated at a specific timestamp T with a replacement item at a different rate and tax rules When the swap is confirmed Then the system calculates the price difference using the remaining rental window from T to the original end time And pro-rates using minute-level precision, rounds to the currency minor unit, and applies applicable taxes and discounts And issues either an incremental charge or a refund for the net difference And records the calculation breakdown (old vs new rates, time basis, taxes, discounts, net delta) on the booking
Stripe PaymentIntent Update Without Charge Duplication
Given the booking has an existing Stripe PaymentIntent for usage charges When a swap changes the rental amount by Δ Then the existing PaymentIntent is updated or a single new PaymentIntent is created solely for Δ based on payment method capabilities And there is at most one captured charge representing the final rental amount per swap attempt And the PaymentIntent(s) include metadata booking_id, swap_id, old_lender_id, new_lender_id, and amounts_before_after And idempotency keys are used to prevent duplicate charges on retries
Deposit Hold Transfer Between Lenders Without Premature Release
Given an active deposit hold is authorized for the original lender and a required deposit exists for the replacement item When the swap is confirmed Then the system authorizes the new required deposit for the replacement lender before releasing or reducing the original hold And at no point does the effective held amount drop below the required deposit for the active lender And if the required deposit decreases, the excess is released within 5 minutes after successful transfer And the active deposit reflects the replacement lender as payee/descriptor post-transfer
Additional Authentication for Increased Deposit
Given the swap increases the required deposit amount and the payment method requires SCA When Stripe returns requires_action on the deposit authorization Then the user is prompted with a 3DS challenge within the app and can complete authentication without losing swap context And on successful authentication the swap proceeds; on failure or timeout the swap is aborted and the prior booking state is preserved And the user sees a clear message indicating the outcome and next steps
Rollback on Payment or Deposit Failure
Given a swap attempt that fails at any payment, deposit authorization, capture, or fee transfer step When the failure is detected Then the booking remains with the original lender, the original calendar reservation is restored, and payment/deposit states revert to pre-swap values And no new charges are captured, no deposit ownership is changed, and any partial authorizations are voided or released And the system logs the failure with a retry-safe idempotency key and emits a user-visible error
Platform Fee Recalculation and Payout Alignment
Given platform fees are configured as percentage and/or fixed amounts When a swap changes the rental amount or lender Then platform fees are recalculated based on the final rental amount and applied once And Stripe application_fee_amount and connected account transfers reflect the recalculated fees and lender payouts And fee adjustments are visible in the admin ledger and in the user and lender receipts
Transparent Receipts and In-App Confirmations
Given a swap completes successfully When the transaction is finalized Then the borrower receives an itemized receipt and in-app confirmation within 60 seconds showing original item, replacement item, time remaining, price delta, taxes, platform fees, deposit hold before/after, and final captured/held amounts And both the original and replacement lenders receive confirmations showing their respective payout impact and deposit status And the booking timeline is updated with a timestamped swap event containing the full calculation breakdown and links to Stripe charge and authorization IDs
Distance & Availability Controls
"As a borrower in a dense city, I want alternates filtered by practical travel time and pickup windows so that swaps are feasible."
Description

Define and apply practical distance and availability constraints for alternates. Supports user-specific and org-level thresholds (radius or travel time) based on saved locations (home, job site) and item size/transport mode. Filters alternates by real-time calendar availability and pickup window feasibility; offers fallback suggestions (expand radius, shift window) if no matches are found. Settings are configurable per user and per HOA/tenant group.

Acceptance Criteria
User Distance Threshold from Saved Location
Given the user has saved locations Home and Job Site and a radius threshold of 3 miles When they select Job Site as the search origin and request alternates Then only alternates within 3 miles of Job Site are returned and those beyond 3 miles are excluded Given the user switches threshold type to travel time of 15 minutes with transport mode Driving When alternates are fetched Then only alternates with ETA by Driving of 15 minutes or less from the selected saved location are returned Given the user changes the selected saved location When alternates are refetched Then the origin is updated and the result set reflects the new location without stale entries
Org-Level Threshold Overrides and Defaults
Given an HOA group sets a default radius of 2 miles with override allowed and the user has no personal setting When alternates are fetched Then the 2 mile default is applied Given the same HOA default and the user sets a personal radius of 5 miles When alternates are fetched Then the personal 5 mile threshold is applied Given the HOA defines a maximum radius cap of 4 miles When a user sets a personal radius of 6 miles Then 4 miles is enforced for filtering and the UI indicates that an org cap is applied
Transport Mode and Item Size–Based Thresholds
Given transport mode is Bike and threshold type is travel time of 20 minutes When alternates are fetched Then travel times are computed using Bike routing and only alternates with Bike ETA of 20 minutes or less are returned Given item size is Oversized and transport mode is Walking When alternates are fetched Then alternates marked vehicle required are excluded and the user is prompted to change transport mode Given item size is Small and transport mode is Scooter When alternates are fetched Then alternates incompatible with Scooter pickup are excluded
Real-Time Calendar Availability Filtering
Given the user requests a pickup window on 2025-08-26 from 10:00 to 11:00 When alternates are fetched Then only alternates whose calendars are free for the entire requested window are returned Given an alternate has a booking that overlaps any minute of the requested window When results are computed Then that alternate is excluded Given the inventory calendar updates and an alternate becomes unavailable When the user refreshes results Then the unavailable alternate is removed from the list
Pickup Window Feasibility with Travel Time
Given the one way travel time from the selected origin to an alternate is 18 minutes and the requested pickup window is 15 minutes wide When feasibility is evaluated Then that alternate is excluded as infeasible for the requested window Given an alternate meets calendar availability but ETA arrival would occur after the window end When results are computed Then the alternate is excluded Given the requested pickup window starts in 10 minutes and the user threshold is travel time 20 minutes When results are computed Then alternates with ETA greater than the time until the window start are excluded
Fallback Suggestions When No Alternates Match
Given no alternates satisfy the distance or availability constraints When the result set is empty Then the system displays actionable suggestions to expand radius or travel time to the next step and to shift the pickup window to the earliest feasible time Given the user taps Expand radius to 5 miles When the search reruns Then results use a 5 mile threshold and a reversible indicator shows the applied expansion Given the user taps Shift pickup by 30 minutes When the search reruns Then the new pickup window is applied and matching alternates are returned if available
Settings Configuration, Scope, and Persistence
Given a user updates their personal distance threshold and saves When they perform a new search or reopen settings Then the saved value persists across sessions and devices Given an HOA admin updates org level defaults When any member performs a search Then the new defaults are applied according to the override and cap rules Given a non admin member attempts to edit org level settings When they access settings Then org level controls are not editable Given a user adds a saved location named Job Site B and selects it as origin When alternates are fetched Then distance and ETA calculations use Job Site B for filtering
Owner Notifications & Consent Rules
"As a lender, I want to be informed and able to approve swaps impacting my items so that I maintain control of my inventory."
Description

Notify the original lender of release and the new lender of assignment with full booking details. Support configurable consent: some owners can require approval before the swap finalizes, with SLA timers and auto-expiry. Deliver in-app, email, and SMS updates respecting user preferences and quiet hours. Ensure that calendars and holds are only finalized after required consents, and provide a streamlined approval UI for lenders.

Acceptance Criteria
Notify Original Lender on Release Request
Given a swap is initiated that releases an item from the Original Lender And the Original Lender has notification preferences and quiet hours configured When the swap is initiated Then create an in-app inbox message immediately with booking ID, item name, borrower first name, requested swap time window, pickup/return windows, location, cost delta, and deposit hold summary And if current time is within quiet hours for email/SMS, queue those messages for delivery at quiet-hour end; otherwise send immediately And record a send attempt per channel with timestamp and delivery status
Consent Gate Before Finalization
Given the Original and/or New Lender requires consent for swaps When a swap is initiated Then set the booking status to Pending Owner Consent And do not modify any lender calendars or create/adjust Stripe holds And present an approval request to each required owner with an SLA timer visible to them And show the borrower a Pending state with no calendar changes
Auto-Expiry and Decline Handling
Given a swap requires owner consent with an SLA of N minutes When the SLA timer expires without any required owner approving Then auto-expire the swap request, leaving original booking and calendars unchanged And release any provisional holds created for the swap And notify borrower and all involved lenders of expiry per preferences and quiet hours When any required owner declines before SLA expiry Then immediately cancel the swap request with the same effects and notifications
Approval UI One-Tap Flow
Given a lender opens the approval request from a deep link or the in-app inbox When they tap Approve Then finalize the swap within 5 seconds, updating calendars, assigning the new lender, and adjusting Stripe holds atomically And send success notifications to borrower, original lender, and new lender per preferences and quiet hours When they tap Decline Then cancel the swap request and notify all parties And persist an audit record of the decision with actor, timestamp, and booking ID
Notify New Lender on Assignment
Given a swap assigns to a New Lender When assignment is finalized Then send notifications per preferences and quiet hours (in-app immediately; email/SMS queued if within quiet hours) including booking ID, item, borrower first name, pickup/return windows, location rules, payout amount, deposit hold, and cancellation window And deliver at least one channel within 60 seconds of finalization (in-app immediately) And record delivery outcomes per channel
Calendar and Hold Finalization Rules
Given all required consents are received When the swap is approved Then update both lenders’ calendars to reflect release and new assignment with no overlapping conflicts And create or adjust Stripe deposit holds to match the new assignment And if any calendar or payment update fails, roll back all changes and notify all parties with an error reference And mark the booking status as Swapped with the approval timestamp
Respect Preferences and Quiet Hours
Given a user has specified notification channels and quiet hours When sending any swap-related notification Then only use enabled channels and suppress SMS/email during quiet hours, queuing them to send when quiet hours end And never send more than one notification per event per channel And log all notifications with a correlation ID for the swap
Swap Audit & Policy Compliance
"As an organizer, I want traceability and policy enforcement around swaps so that the system remains fair and disputes can be resolved."
Description

Maintain a detailed audit log of all swap events (who, when, what changed, rationale) for support and dispute resolution. Enforce cancellation, no-show, and swap frequency policies; limit consecutive swaps and flag suspicious patterns. Provide admin dashboards for organizers to review metrics, export logs, and adjust policies. Integrates with reporting and moderation tools to keep the ecosystem trustworthy.

Acceptance Criteria
Audit Log Creation on Swap Event
Given an authenticated borrower initiates a one-tap swap on an existing booking When the swap is confirmed Then a single audit record is persisted within 1 second containing non-null fields: event_id, booking_id, actor_user_id, organizer_id, original_item_id, swapped_item_id, action="swap_confirmed", rationale_text, policy_snapshot_id, timestamp (UTC ISO-8601), outcome_status, correlation_id Given a swap attempt fails policy/validation When the system rejects the swap Then an audit record is persisted with action="swap_rejected", failure_reason_code, evaluated_policy_ids, timestamp, correlation_id Given duplicate client retries for the same swap within 3 seconds using the same correlation_id When the request is processed Then only one audit record is stored (idempotent), and subsequent duplicates are acknowledged without creating additional records
Immutable Audit Log and Ordering
Given an existing audit record When any user attempts to edit or delete it via API/UI Then the operation is denied with 403, and any correction is captured as a new amendment entry referencing prior_event_id with reason_code and timestamp Given multiple audit records exist for a booking When queried by booking_id Then results are strictly ordered by timestamp then sequence_number with no gaps or overlaps, and each record contains integrity_hash and previous_integrity_hash enabling chain verification that passes integrity check Given retention_policy_months = 24 When records exceed retention Then records are soft-deleted with a tombstone entry (action="tombstone") and are excluded from default queries but included in export if include_tombstones=true
Policy Enforcement: Swap Frequency and Consecutive Swaps
Given default policy: max_consecutive_swaps_per_booking=2, max_user_swaps_24h=5, cooldown_after_limit_hours=12 When a user attempts a swap that would exceed any limit Then the swap is blocked with HTTP 409 and user_message_code="SWAP_LIMIT_REACHED", and an audit record is written with action="policy_block", policy_snapshot_id, counters_before_after, cooldown_until Given an organizer updates swap frequency limits in Admin > Policies When a subsequent swap is evaluated Then the new limits take effect within 60 seconds, are captured in policy_snapshot_id, and do not retroactively alter past decisions Given a user remains within configured limits When submitting a swap Then the swap proceeds and the audit record includes counters_before_after and policy_evaluation="pass"
Policy Enforcement: Cancellations and No-Shows
Given late_cancel_threshold_hours=3, late_cancel_penalty_capture_pct=15, cooldown_hours=24 When a borrower cancels a booking inside the threshold Then the system captures 15% of the existing Stripe deposit hold, applies a 24h swap cooldown, sends a user notification, and records an audit entry with payment_intent_id, penalty_type="late_cancel_capture", penalty_amount, cooldown_until Given a no-show is auto-detected (no check-in within 30 minutes of pickup start) or marked by organizer When the no-show is recorded Then the system captures 25% of the deposit hold, applies a 72h cooldown, notifies the borrower, and records audit fields: detection_method, penalty_type="no_show_capture", penalty_amount, cooldown_until Given an admin overrides or refunds a penalty When the override is approved Then the Stripe reversal is executed referencing the original charge, the borrower is notified, and an audit entry with action="penalty_override", admin_user_id, justification_text, and reversal_reference is created
Suspicious Pattern Detection and Flagging
Given a borrower completes 4 or more swaps within a 6-hour window with 3 or more initiated <30 minutes before pickup When the 4th qualifying event occurs Then the system creates a flag type="SUSPICIOUS_LATE_SWAPS" with evidence fields (counts, timestamps) and places a case into the moderation queue within 10 seconds, with an audit entry linking flag_id Given signals indicate multiple accounts sharing device_fingerprint or payment_token_hash across neighborhoods and exceeding configured thresholds When thresholds are met Then a flag type="SUSPICIOUS_MULTI_ACCOUNT" is created with hashed identifiers (no raw PII), and access is restricted to authorized roles; an audit entry records flag details and access scope Given a flag is opened When viewed in the admin UI Then it shows SLA fields (first_response_due<=24h), status transitions (open, investigating, resolved), and all transitions are audit logged
Admin Dashboard: Review, Filter, Export, and Policy Adjustments
Given an organizer with admin role opens the Swap Audit dashboard for a community with ≥50,000 records When the page loads with default 30-day date range Then results render with server-side pagination and filters (date_range, user_id, item_id, action, outcome_status, policy_violation, flag_type) in ≤3 seconds Given an export request (CSV or JSON) for up to 100,000 filtered records When the export is initiated Then a downloadable file is produced in ≤60 seconds with a stable schema; timestamps are UTC ISO-8601; row count equals the filtered count; the link expires in 24 hours Given a policy edit is saved in the UI When the change is validated Then it is versioned with policy_version_id, takes effect within 60 seconds, is reversible via rollback to a prior version, and a policy_change audit entry is created including before/after values and admin_user_id Given a non-admin attempts to view or export audit data When access is checked Then the request is denied with 403 and an access_denied audit entry is created
Reporting and Moderation Integrations
Given webhook integrations are enabled When an audit event or flag is created Then a signed HMAC-SHA256 webhook is POSTed within 5 seconds including idempotency_key and minimal payload (no raw PII; include user_id, booking_id, event_type, timestamps); on failure, retry up to 3 times with exponential backoff, then route to DLQ visible in admin UI Given the reporting API is queried for audit logs When clients paginate and sort by timestamp Then responses are consistent and stable, enforce rate limit 60 req/min per API token with 429 and Retry-After on excess, and no record duplication across pages when using cursor-based pagination Given privacy constraints When emitting events to external systems Then payloads exclude emails, phone numbers, and payment instrument details; any identifiers are hashed; compliance flags (e.g., export_consent) are respected, and events violating constraints are blocked and logged with action="privacy_block"

Route Stitch

Optimizes pickup and return windows into an efficient loop near your home or commute, respecting building quiet hours and HOA rules. Less backtracking, fewer missed windows, and faster starts for each step of your project.

Requirements

Anchor Points & Preferred Windows
"As a borrower, I want to set my home/work anchors and availability so that my pickups and returns fit my schedule with minimal detours."
Description

Enable users to define home/work anchor points and preferred availability windows that Route Stitch uses to build an efficient pickup/return loop. Integrates with Sharehood bookings to ingest confirmed pickup/return windows, adds configurable service/buffer times (e.g., lobby access, elevator time), and constrains the loop to start/end near the chosen anchor. Supports commute-direction preference (e.g., outbound vs. inbound), calendar sync, and produces an ordered, timeboxed itinerary consumable by mobile and web clients.

Acceptance Criteria
Anchor Selection and Route Start/End Proximity
- Given the user has home and work anchors configured and selects Home as the route anchor, When Route Stitch generates the loop, Then the first segment starts within the configured anchor radius (default 200 m) of the Home anchor and the final segment ends within the same radius. - Given an anchor radius override value is provided (e.g., 100 m), When the route is generated, Then both start and end proximity checks use the override. - Given multiple feasible sequences exist, When evaluating routes, Then the algorithm selects the sequence with minimal total travel time while satisfying anchor proximity constraints. - Given no sequence can satisfy anchor proximity due to windows or constraints, When route generation is attempted, Then the system returns failure code ROUTE_NO_ANCHOR_PATH and lists the blocking constraints.
Preferred Availability Windows Enforcement
- Given user-defined preferred availability windows for weekdays 18:00–21:00 and building quiet hours 22:00–07:00, When generating the route, Then no pickup/return timebox begins or ends during quiet hours and all stops are scheduled within preferred windows unless overridden by booking constraints. - Given a stop has a booking window 17:30–18:15 and a 10-minute service time, When scheduled, Then the arrival time is between 17:30 and 18:05 so that departure occurs no later than 18:15. - Given a stop cannot fit into preferred windows but fits within booking window and quiet hours, When "Allow outside preferred windows" is true, Then the stop is scheduled and flagged with outside_preference=true in the itinerary. - Given no feasible placement exists respecting booking windows, quiet hours, and service times, When generating the route, Then the system surfaces conflict details per stop with suggested nearest viable times.
Booking Window Ingestion and Conflict Handling
- Given two Sharehood bookings with confirmed pickup/return windows, When Route Stitch runs, Then it ingests only confirmed windows and ignores cancelled or tentative bookings. - Given two bookings overlap after adding travel plus service/buffer times, When generating, Then the algorithm reorders stops to avoid overlap; if overlap persists, it marks the conflicting stops with conflict=true and includes a resolution suggestion with ±15-minute alternatives. - Given a booking is updated in Sharehood, When a re-sync occurs, Then the itinerary is recalculated within 5 seconds and version increments by 1 with the route_id preserved. - Given a booking is deleted, When re-sync runs, Then the corresponding stop is removed and downstream times are reflowed; calendar events are updated accordingly.
Service/Buffer Time Configuration Application
- Given global service time=5 minutes and per-location buffer=8 minutes (elevator/lobby), When scheduling a stop at that location, Then the stop's timebox includes 13 minutes of non-travel time. - Given a user overrides service time for an individual stop to 0 minutes, When regenerating the route, Then the override is applied only to that stop. - Given total non-travel time would push a stop outside its booking window, When generating, Then the system shifts the arrival earlier if feasible; otherwise flags the stop unschedulable with code WINDOW_VIOLATION. - Given no service/buffer config is provided, When generating, Then defaults of service=5 minutes and buffer=0 minutes are applied.
Commute Direction Preference Ordering
- Given commute preference is Outbound (home→work) with Work selected as route end, When generating, Then the loop starts near Home anchor and ends within anchor radius of the Work anchor. - Given commute preference is Inbound (work→home), When generating, Then the loop starts near Work anchor and ends near Home anchor within the configured radius. - Given commute preference is None, When generating, Then the loop starts and ends at the selected single anchor. - Given the commute preference cannot be honored due to windows or constraints, When generating, Then the system switches to single-anchor mode or returns ROUTE_COMMUTE_INFEASIBLE with rationale.
Calendar Sync of Itinerary Events
- Given the user has connected Google Calendar, When a route is created, Then individual events are created for each stop with titles "Pickup: {item}" or "Return: {item}", correct start/end times, location, and a 10-minute default reminder. - Given a route is updated, When sync runs, Then existing calendar events are updated in place using a stable external_event_id; no duplicate events are created. - Given the user disconnects calendar, When sync runs, Then previously created events remain but no further updates are attempted; the app displays sync_status=disconnected. - Given the user time zone differs from the booking time zone, When syncing, Then event times are converted to the user's calendar time zone correctly.
Ordered, Timeboxed Itinerary API/Client Consumption
- Given a route is generated, When retrieving via API, Then the response includes an ordered array of stops with fields [stop_id, type, item_id, location, arrival_time, departure_time, service_minutes, travel_minutes_from_prev, outside_preference, conflict, notes] and a route_summary with [route_id, version, start_anchor, end_anchor, total_travel_minutes]. - Given the itinerary is viewed on mobile and web, When rendered, Then both clients display the same order and timeboxes within ±1 minute variance due to rounding. - Given network is offline after the route is generated, When opening the mobile app, Then the last generated itinerary is available from cache. - Given a typical urban route (≤8 stops), When generating, Then 95th percentile route computation completes in ≤2 seconds on server; timeouts surface ROUTE_TIMEOUT with retry-after suggestion.
Constraint-Aware Route Optimization
"As a borrower, I want the app to stitch my pickups and returns into an efficient loop that respects all time windows so that I can start projects faster without backtracking."
Description

Implement a TSP/VRP-with-time-windows solver that sequences pickups and returns to minimize travel time and backtracking while honoring time windows, item pair constraints (pickup precedes return), per-stop service times, max detour thresholds, and building/HOA rules. Provides deterministic outputs with tie-breaking for fairness, returns infeasibility reasons with actionable alternatives (e.g., suggest new windows), and exposes a versioned API for clients. Caches map distances, supports multi-modal travel estimates, and scales to 20–30 stops per loop.

Acceptance Criteria
Route Efficiency and Backtracking Minimization
Given a 10-stop symmetric test instance with a known optimal solution When the solver runs with the provided inputs and a fixed seed Then the returned sequence matches the known optimal sequence and total travel time is within 0.5% of the known optimum Given the same inputs and a naive nearest-neighbor baseline When comparing objective values Then solver_route.total_time <= baseline.total_time AND solver_route.total_distance <= baseline.total_distance Given a linear corridor instance (east-to-west indexed stops) without conflicting time windows When the solver computes a route Then the produced order is monotonic along the corridor and backtracking_count == 0
Time Windows and Quiet Hours Compliance
Given stops with explicit [start,end] time windows and building/HOA quiet hours When a schedule is produced Then every arrival_time >= window.start AND departure_time <= window.end AND no service interval overlaps any quiet hours interval Given a stop whose feasible arrival would violate quiet hours When scheduling Then the stop is shifted within allowed windows or marked infeasible with reason=QUIET_HOURS_VIOLATION Given overlapping time windows that cannot all be satisfied When the solver completes Then the response includes infeasibility with conflicting_stop_ids and reason=WINDOW_VIOLATION
Pickup-Return Precedence and Service Times
Given any item pair with pickup_stop_id=P and return_stop_id=R When the schedule is produced Then P occurs before R and R starts after P.completion_time Given per-stop service_time s_i for all stops When computing arrival and departure times Then departure_time_i = arrival_time_i + s_i, and all downstream arrivals reflect accumulated service times Given that service_time propagation causes a window miss When no feasible reorder exists Then the affected stop is flagged with reason=WINDOW_VIOLATION and is included in infeasibility.explanations[]
Multi-Modal Travel Estimates and Max Detour Thresholds
Given travel_mode in {walk,bike,car} with configured speed profiles and routing constraints When estimating inter-stop travel times Then ETA estimates are mode-specific and within ±10% of the provider’s ground-truth for the same mode Given a base_path and max_detour_time=T and max_detour_distance=D When constructing the loop Then total detour relative to base_path <= T and <= D; any violating stop is excluded with reason=DETOUR_LIMIT and, if possible, grouped into an alternative window suggestion Given a commute anchor and direction (outbound/inbound) When generating the loop Then the first and last scheduled points lie within 200m of the configured anchor
Deterministic Output and Fair Tie-Breaking
Given identical inputs (stops, constraints, distances), solver_version, and fixed seed When the solver runs five times Then the exact same sequence, arrival times, and objective value are returned across runs Given multiple equal-cost next-stop candidates When tie-breaking is applied Then ordering is deterministic by fairness_key=(last_served_at, borrower_priority, stop_id) ascending Given two runs on consecutive planning_date values with unchanged inputs When tie-breaking is applied Then the round-robin offset rotates equal-cost candidates across days while remaining deterministic per day
Infeasibility Explanations with Actionable Alternatives
Given no feasible route exists under provided constraints When the solver responds Then HTTP 422 is returned with infeasibility.explanations[] listing per-stop violated constraints with codes in {WINDOW_VIOLATION, QUIET_HOURS_VIOLATION, PRECEDENCE_VIOLATION, DETOUR_LIMIT, CAPACITY_LIMIT} Given a stop listed in infeasibility.explanations[] When alternatives are computed Then up to 3 feasible alternative time windows within the next 7 days are returned, each validated by a dry-run feasibility check Given the client accepts one suggested alternative window When rerunning optimization Then a feasible plan is returned or a reduced infeasibility set is produced with updated explanations
Versioned API, Distance Caching, and Scalability
Given a request to /route-stitch/v1/optimize with a v1-compliant payload When processed Then HTTP 200 is returned with fields {route, schedule, objective, infeasibility[], solver_version, api_version="v1"}; if version is missing/unsupported, HTTP 400 is returned Given repeated identical OD pairs within cache_ttl When executing multiple optimizations Then external map distance calls are reduced by >=90% with cache_hit_ratio >=80%; when provider data_version changes, relevant cache entries are invalidated Given 30 stops with time windows and constraints on 4 vCPU/8GB RAM When the solver runs Then median latency <= 2s, p95 latency <= 5s, memory usage < 1 GB, and objective within 2% of an exact solver on a 12-stop benchmark subset
Quiet Hours & HOA Compliance Engine
"As a building organizer, I want pickup and return windows to automatically avoid quiet hours so that residents comply with HOA policies without manual policing."
Description

Create a rules engine that ingests property-level constraints (quiet hours, loading zones, lobby desk hours, elevator reservation requirements) from building profiles and organizer inputs, and applies them as hard/soft constraints during route planning. Blocks conflicting bookings, flags borderline cases with warnings, and proposes compliant alternatives. Maintains an auditable policy log, supports per-building overrides, and localizes messaging so users understand why certain windows aren’t available.

Acceptance Criteria
Block Bookings Violating Quiet Hours
Given a building profile with quiet hours 21:00–07:00 local and a route step pickup at 21:15 When the user attempts to confirm the booking Then the engine rejects the step, blocks checkout, and displays the reason "Pickup violates quiet hours (21:00–07:00)" and highlights the conflicting time on the calendar And a policy log entry is recorded with rule ID, building ID, decision=block Given a route spans multiple buildings with differing quiet hours When optimizing the sequence Then the engine enforces each building’s hard quiet-hours window independently and schedules no step inside its building’s quiet hours Given the user’s device time zone differs from the building’s When evaluating constraints Then the engine uses the building’s local time zone for all comparisons
Respect Loading Zones and Lobby Desk Hours
Given a building profile with loading zone hours 10:00–16:00 and lobby desk hours 08:00–20:00 When the route includes an item requiring loading zone access Then pickup and return windows are scheduled only within the overlap 10:00–16:00 And any conflicting requested time is blocked with an explanation referencing both constraints Given no overlap exists on the requested day When planning Then the booking is blocked and compliant alternatives are proposed on the next available days with overlap Given a user selects curbside pickup outside loading zone hours When confirming Then the system blocks the step and displays "Loading zone unavailable at selected time"
Elevator Reservation Requirement Handling
Given a building requires an elevator reservation for items tagged Large and no reservation exists for 14:00–15:00 When planning the route Then the engine blocks scheduling in that window and proposes the next three reservation-backed slots within 72 hours Given an organizer provides a valid reservation ID for 15:00–16:00 When planning Then the step is scheduled within that slot and the reservation ID is stored with the route and in the policy log Given ETA variance of ±10 minutes could breach the reservation When optimizing Then the engine adds a 15-minute buffer and warns if the buffer exceeds the reservation window, requiring user acknowledgement to proceed
Soft-Constraint Warnings for Borderline Windows
Given building quiet hours begin at 21:00 and the soft-warning threshold is 30 minutes before start When a user selects a 20:40–20:55 window Then checkout is allowed but a warning banner appears and requires explicit user acknowledgement before payment Given the user changes the time to 21:05 When re-validating Then the booking is blocked with a hard constraint message and no payment is allowed Given an organizer adjusts the threshold to 15 minutes for this building When planning Then warnings trigger only for starts at or after 20:45 and before 21:00
Propose Compliant Alternative Windows
Given a requested window conflicts with any hard constraint When the user attempts to book Then the system returns at least three compliant alternative windows within the next 48 hours, ordered by minimal additional travel time and earliest start, each annotated with the satisfied constraints Given no compliant slots exist within 48 hours When searching Then the system returns "No compliant slots in next 48 hours" and offers to expand the search range (date and geography) Given the route has multiple stops When generating alternatives Then the engine preserves compliant steps and only adjusts conflicting ones while maintaining a continuous loop
Auditable Policy Log Entries
Given any constraint evaluation occurs during planning When a decision is made (allow|warn|block) Then an immutable log entry is created with fields: timestamp (ISO-8601 UTC), user ID, route ID, building ID, rule ID, rule version, decision, evaluated times in building local, and message key; the entry is retrievable by an admin API within 2 seconds Given a booking is modified or canceled When re-evaluating constraints Then a new log entry is appended capturing the diff of evaluated constraints and decision changes; prior entries remain unchanged Given services run on different clocks When logging Then timestamps are normalized to UTC and include building-local offsets in the payload
Per-Building Overrides and Messaging Localization
Given an organizer downgrades the Loading Zone Hours rule from hard to soft for Building A When planning Then the engine emits warnings instead of blocks for violations in Building A and records the override in the policy log with actor ID and timestamp Given a user device locale is es-ES and a block occurs When rendering the message Then the reason is shown in Spanish using the correct message template and variables (hours, rule name) and falls back to English only if es-ES is unavailable Given localization files are updated to a new version When messages are rendered Then the correct versioned template is used and all placeholders are substituted; no raw keys or missing translations appear
Real-time Re-Routing & Delay Handling
"As a borrower, I want my route to auto-adjust if I’m delayed or a stop changes so that I still complete pickups efficiently and stay compliant."
Description

Continuously monitor trip progress via passive location pings and user check-ins, ingest traffic data and lender cancellations, and dynamically re-optimize remaining stops. Adjust ETAs and window commitments, propose micro-reschedules within policy, and preserve compliance with HOA rules. Provide offline-friendly guidance with countdown timers and deterministic next steps when connectivity is poor. Log all changes for transparency and dispute resolution.

Acceptance Criteria
Passive Pings & Check-Ins Track Progress
Given a borrower starts a Route Stitch trip with location permissions enabled When the device is moving faster than 2 km/h Then the app records passive location pings at least every 60 seconds with accuracy ≤ 50 meters and queues them for upload And when stationary for 3+ minutes Then the ping interval backs off to ≤ 5 minutes And when arriving within 50 meters of a scheduled stop Then the app prompts a one-tap check-in and records it with timestamp And if permissions are denied Then the system requires manual check-ins at each stop before continuing
Traffic Delay Triggers Dynamic Re-Optimization
Given an active trip with 2 or more remaining stops and live traffic ingest enabled When predicted delay to the next stop exceeds 5 minutes or 15% of segment ETA, whichever is greater Then the system re-optimizes the remaining stop order within 2 seconds on-device or 5 seconds server-side And recalculates ETAs for all remaining stops And ensures no proposed route violates configured HOA quiet hours or building access windows And displays a change badge and updated ETAs to the borrower within 1 second of computation
Lender Cancellation Mid-Route
Given a lender cancels an appointment for a not-yet-visited stop When the cancellation event is received Then the stop is marked canceled and removed from the route within 3 seconds And the system proposes one of: an alternate lender within 1 km that meets the same item and policy windows, or a micro-reschedule within the same day And affected ETAs are updated and notifications are sent to the borrower and any impacted lenders within 10 seconds And no new plan violates HOA/quiet-hour rules
Micro-Reschedules Within Policy
Given a route with overlapping windows or delays When a micro-reschedule of 10–30 minutes would resolve conflicts and maintain compliance Then the system proposes up to 2 micro-reschedules per stop with a clear reason code (traffic, cancellation, overlap) And requires one-tap borrower confirmation for changes > 10 minutes and lender confirmation if outside the original commitment window And automatically applies changes if both parties accept within 5 minutes, otherwise reverts to the prior plan and flags for manual escalation And enforces a max of 2 micro-reschedules per stop per day
Offline Guidance With Deterministic Next Steps
Given network connectivity drops below 2G or is unavailable When offline is detected Then the app switches to offline mode within 3 seconds, showing the next stop, static map snapshot, turn list, and a countdown timer to the window start/end And provides deterministic next-step prompts (arrive, check in, contact lender via cached number) without requiring network And queues all pings, check-ins, and plan changes locally with timestamps and persists them across app restarts And syncs queued events within 10 seconds of reconnection and reconciles with server without data loss
HOA & Quiet Hours Compliance Preservation
Given HOA quiet hours and building access rules are configured per stop When re-optimization would schedule arrival within a restricted window Then the system avoids routing to that stop in that window and proposes compliant alternatives or micro-reschedules to the earliest allowed time And blocks borrower overrides that would violate rules, displaying the next allowed time And validates compliance before publishing new ETAs or commitments
Transparent Audit Log for Route Changes
Given any change to route, ETAs, stop order, windows, or commitments When the change is computed or accepted Then an immutable audit entry is written capturing timestamp (UTC), actor (system/borrower/lender), previous value, new value, reason code (traffic/cancel/offline/user), and correlation ID And the borrower and lenders can view a chronological log within the trip timeline And the log is exportable as JSON within 5 seconds on request And entries are retained for at least 180 days
Two-Sided ETA & Window Notifications
"As a lender, I want accurate arrival windows and updates so that I can be ready and avoid missed pickups."
Description

Deliver precise, rate-limited notifications to borrowers and lenders with upcoming window reminders, live ETAs, and check-in prompts. Support push, SMS, and email with user preferences, localized time zones, and deep links to reschedule or navigate. Syncs with the optimizer to reflect re-routes in real time, and exposes a webhook for organizer dashboards to visualize arrival boards.

Acceptance Criteria
Borrower Pre-Window Reminder (Rate-Limited, Multi-Channel)
Given a borrower has a confirmed pickup or return window starting in 30 minutes and has enabled SMS and Push When the system time reaches T0-30 minutes Then send exactly one reminder per selected channel within 60 seconds including localized start/end times, booking ID, and deep links to Reschedule and Navigate Given subsequent reminder triggers occur within 15 minutes for the same booking When the notification job runs Then suppress duplicates using an idempotency key and log a single reminder event per booking per 15-minute window Given a channel delivery failure is returned within 30 seconds When retries are attempted Then retry up to 3 times with exponential backoff and record final delivery status without violating the 15-minute rate limit
Live ETA Update After Re-Route (Two-Sided)
Given the optimizer applies a re-route producing a new ETA with |ΔETA| ≥ 2 minutes for an active booking When the re-route is committed Then send an ETA update to both borrower and lender within 30 seconds, displaying the new ETA and ±Δ, and include Navigate and (if pre-start) Reschedule deep links Given multiple re-routes occur within a 10-minute span for the same booking When updates are evaluated Then coalesce updates to at most one notification per 5 minutes per user per booking Given the notification is sent When the user opens the app Then the in-app ETA badge reflects the new ETA within 5 seconds and SMS/email bodies show localized times
Notification Quiet Hours and HOA Rules Enforcement
Given a user has quiet hours set (e.g., 22:00–07:00 local) or organizer blackout rules in effect When a non-critical reminder is scheduled during that interval Then defer the reminder to the end of quiet hours/blackout and log the defer reason code Given a pickup/return window starts within the quiet hours interval When notifications must be sent Then deliver a single silent push and low-priority SMS/email with a "quiet hours" label and do not send additional reminders during that interval Given a deferred notification exits quiet hours When sending resumes Then dispatch within 60 seconds and respect rate limits and user channel preferences
Deep Links: Reschedule and Navigate Actions
Given a recipient opens a Reschedule link from a notification and the app is installed When the link is tapped Then open the Reschedule screen with booking ID preloaded and show optimizer-synced alternative windows within 2 seconds Given the app is not installed When the Reschedule link is tapped Then open a mobile-web fallback with the same context and complete one-tap auth via a signed token Given a recipient taps Navigate When the link is opened Then launch the device default maps app with the pickup/return address and earliest valid arrival time prefilled; provide an in-app prompt to refresh if the route updates Given any deep link is generated When security is validated Then the link is signed, expires within 24 hours, is single-use, and all clicks are attributed to booking ID and channel
Time Zone Localization for Notifications
Given borrower and lender are in different time zones When a notification is rendered Then display all times in the recipient’s local time with explicit zone abbreviation (e.g., 3:30 PM MDT) and include an ISO-8601 UTC timestamp in metadata Given a daylight saving time change occurs within a window When computing start/end times Then apply IANA timezone rules and display the correct offset; validation includes test cases across US, EU, and AU regions Given a user has selected a 12h or 24h preference When formatting times Then render times according to that preference across push, SMS, and email
Organizer Arrival Board Webhook
Given an organizer has registered a webhook with a verified signing secret When events occur (window_reminder_sent, eta_updated, check_in_started, check_in_completed) Then POST JSON payloads within 5 seconds including booking ID, party role, ETA, window, and an x-sharehood-signature (HMAC-SHA256) header; delivery is at-least-once Given the webhook endpoint returns 5xx When retries are scheduled Then retry up to 6 times over 15 minutes with exponential backoff and jitter; stop on 2xx; respect Retry-After on 429; do not retry on other 4xx Given multiple events are emitted for the same booking within 2 minutes When dispatching Then preserve order via sequence and event_time, include an idempotency key, and keep payload size ≤ 1 MB Given developers use the test tools When invoking the sandbox endpoint Then signatures, ordering, retry behavior, and sample payloads validate successfully
Check-In Prompts at Start and Completion
Given a pickup or return window starts and the borrower has not tapped "On My Way" When T0 occurs Then send a check-in prompt at T0 and exactly one follow-up at T0+10 minutes if still inactive, respecting rate limits and quiet hours Given the borrower taps "On My Way" When the state updates Then notify the lender immediately with a live ETA and set the booking state to en_route Given the borrower or lender confirms "Handed Off" When the confirmation is recorded Then mark the item status accordingly, cease further check-in prompts, and emit check_in_completed to the webhook within 10 seconds
Deposit Hold & Window Coordination
"As a borrower, I want deposit holds to align with my stitched schedule so that I’m not overcharged for delays outside my control."
Description

Align Stripe deposit holds with stitched route windows by batching holds across multiple items, pre-authorizing before route start, and auto-extending or partially releasing based on real-time progress and policy. Provide clear user messaging for hold status, retry flows on payment failures, and automated release on completed or canceled stops. Ensure compliance with Stripe and regional payment regulations.

Acceptance Criteria
Pre-Route Batch Preauthorization for Multi-Item Route
Given a borrower has a stitched route containing two or more items with defined pickup/return windows and a default payment method on file When the system reaches 10 minutes before the first pickup window start or the borrower taps "Start Route", whichever occurs first Then the system initiates batched deposit preauthorizations via Stripe so the total authorized amount equals the sum of active item deposit requirements, with per-item metadata linking each authorization to its item and route And any required SCA challenge is presented once and, upon success, the preauthorization completes within 5 seconds per attempt And the route displays Hold Status = "Preauthorized" with total amount, timestamp, and last-4 of the payment method And if any item’s preauthorization fails, that item is flagged with Hold Status = "Failed", the route Hold Status = "Action Needed", and the borrower is prompted to retry or change payment method without losing existing successful holds
Per-Stop Partial Release After Completion
Given an active aggregated deposit hold for a route with multiple remaining items When a stop is marked Completed by both parties or auto-completed via location + time confirmation Then the system reduces the held amount by that item’s deposit within 30 seconds using a Stripe-supported adjustment and sets Hold Status = "Partially Released" And the route and item timelines reflect the new held amount and include an audit entry with Stripe identifiers And when the final stop is completed, the system fully releases the remaining hold within 2 minutes and sets Hold Status = "Released"
Auto-Extend Hold When Route Windows Shift
Given a route has future stops beyond the current hold’s expiration window When the system detects that a hold will expire within 12 hours and at least one stop remains Then it extends or renews the authorization before expiry in compliance with Stripe and issuer constraints, preserving uninterrupted coverage, and records the new expiration timestamp And if extension would exceed the policy maximum hold duration, the borrower is prompted to reauthorize once, and the route is paused until success or timeout (max 15 minutes) And if extension or renewal fails, affected stops are put On Hold, users are notified, and no further items are handed off until a valid hold is in place
Payment Failure Retry and Recovery
Given a preauthorization attempt fails due to a soft decline or network error When the retry policy triggers Then the system retries up to 3 times with exponential backoff (10s, 30s, 90s) and preserves idempotency And the borrower can update or select an alternate payment method and immediately reattempt the preauthorization And if all retries fail or the borrower cancels, the route is set to "Payment Failed", all pending windows are released, any successful holds are voided, and both parties receive notifications
Auto-Release or Partial Capture on Stop Cancellation
Given a stop is canceled before pickup or return and an active hold exists for that item When the cancellation policy requires no fee Then the held amount for that item is released within 2 minutes and Hold Status = "Released" And when the policy requires a fee (e.g., late cancel/no-show), the system captures the policy-defined amount and releases the remainder, issues a receipt to the borrower, and updates payouts to the organizer or lender And all actions are reflected in the audit log with policy reference, captured amount, and Stripe charge or authorization IDs
Real-Time Hold Status Messaging and UI Indicators
Given any change in the hold lifecycle occurs (Preauthorized, Extended, Partially Released, Captured, Released, Failed) When the state changes Then the borrower and relevant organizer or lender see real-time status badges and amounts on the route timeline and item detail within 2 seconds And push, email, or SMS notifications are sent according to user preferences with localized currency, timezone, and clear explanations And the UI meets accessibility standards (contrast ≥ 4.5:1, screen-reader labels present) and supports EN and ES locales
Stripe and Regional Compliance with Audit Logging
Given the system processes deposit holds via Stripe When authorizing, extending, capturing, or releasing holds Then requests use Stripe-recommended APIs with idempotency keys, and no raw card data is stored on Sharehood servers (PCI SAQ A scope) And SCA or 3DS challenges are invoked when required by region or issuer, with fallbacks for out-of-band challenges, and failures do not leave orphaned holds And data retention includes immutable audit logs for 24 months containing user IDs, item IDs, route ID, policy references, amounts, timestamps, and Stripe object IDs accessible to compliance admins

Drift Guard

If an early step runs late or a pickup slips, Drift Guard auto-adjusts the rest of your chain—compressing windows, reordering steps when possible, and coordinating with lenders—so you can still hit your deadline without manual replanning.

Requirements

Real-time Drift Detection & Propagation
"As a borrower on a multi-stop route, I want the system to detect when an early step runs late so that the rest of my bookings adjust automatically and I still meet my final deadline."
Description

Continuously monitors each booking chain step (pickups, handoffs, returns) for lateness or slips and emits drift events that immediately trigger recalculation across the remainder of the chain. Ingests signals from check-in/out actions, lender confirmations, borrower location/geofence arrivals, calendar timestamps, and Stripe deposit/hold state to identify delays against planned start/end times and grace thresholds. Applies configurable tolerances per lender/item, classifies severity, and propagates impact to downstream steps, ensuring the live calendar reflects current reality without manual intervention. Integrates with Sharehood’s booking calendar and smart pickup windows to maintain a single source of truth for timing.

Acceptance Criteria
Detect Delay from Late Pickup Check-In
- Given a step with planned_start=S and grace_minutes=G, when borrower checks in at time T where T > S + G, then system computes lateness_ms = (T - S) and emits DriftDetected{chain_id, step_id, source="check_in", planned_start, actual_start=T, lateness_ms, severity} within 2s of check-in. - Given a step where borrower checks in at or before S + G, then no drift event is emitted and step status remains "on_time". - Given no check-in or geofence arrival by S + G, when S + G + 60s elapses, then system emits MissedStart{source="timer"} with lateness_ms >= 60000 and updates step status to "late".
Propagate Drift to Downstream Steps with Compression
- Given a DriftDetected on step i with lateness L>0, when recalculation runs, then all downstream steps i+1..n are recomputed within 2s, compressing flexible buffers up to each step's configured compression_limit_percent and never reducing any window below min_window_floor_minutes. - Then the recomputed schedule contains no overlaps, respects lender availability windows, and maintains the chain final_deadline when feasible; otherwise the chain is marked deadline_at_risk=true. - Then smart pickup windows are updated to the new start/end times and the live calendar reflects the changes to all viewers and API consumers within 5s of event emission.
Reordering Non-Dependent Steps to Preserve Deadline
- Given two or more downstream steps without dependency constraints, when current ordering would miss final_deadline and an alternative ordering keeps it without violating constraints, then the system selects the alternative ordering that minimizes total slack loss and produces no overlap. - Then the new order, start/end times, and rationale are persisted and included in DriftPropagation{action="reorder", justification} and broadcast within 3s of decision. - Then lenders/borrowers for affected steps receive updated times; if reordering is not feasible, the system sets deadline_at_risk=true with severity="critical".
Tolerance & Severity Classification per Lender/Item
- Given lender/item tolerance_minutes=T and grace_minutes=G, when lateness L is computed, then severity is assigned deterministically: L <= T => "minor"; T < L <= 2T => "moderate"; L > 2T or final_deadline infeasible => "critical". - Given missing tolerance for a lender/item, then default tolerance_minutes=5 is applied and recorded on the event. - Then severity is included on all drift/propagation events and is used to drive propagation rules (e.g., compression for minor/moderate, reorder/at-risk for critical).
Geofence Arrival and Auto Check-In for Pickup
- Given borrower enters pickup geofence with radius=50m and remains for dwell>=30s, then arrival_time=A is recorded; if no manual check-in within 60s of A, auto check-in occurs at A+60s. - When A (or auto check-in) > planned_start + grace_minutes, then a drift event is emitted with source="geofence" (or "auto_check_in"); otherwise the step remains on-time. - Geofence hysteresis is applied (exit threshold >=70m) to prevent flapping; only one auto check-in is created per step; if location permissions are denied, system falls back to timer-based detection without generating false geofence events.
Stripe Deposit/Hold State Drives Drift and Blockers
- Given a step requires a Stripe deposit hold, when the hold fails or expires before planned_start, then within 5s the step is marked state="blocked", a DriftBlocked{reason="deposit_hold"} event is emitted, and downstream steps are marked blocked until unblocked. - When the hold is successfully captured, then within 5s the step unblocks, recalculation runs, and any accrued lateness is recomputed and propagated. - Drift logic reads Stripe state only and never triggers charges/refunds; verified in test mode that no payment-side side effects occur during drift handling events.
Drift Event Emission, Idempotency, and Calendar SLA
- For any new delay signal (check-in/out, lender confirmation, geofence, timer), a drift event is emitted within 2s of signal ingestion and assigned a monotonic sequence_number per chain. - Duplicate signals for the same step producing an effective lateness delta within ±5s and arriving within a 2-minute window are idempotently coalesced (no duplicate state changes or duplicate notifications). - The live calendar/UI/API reflect recalculated times within 5s of the drift event, and a WebSocket broadcast is sent to subscribed clients within 3s; audit logs persist before external broadcasts.
Adaptive Window Compression Engine
"As a borrower, I want Drift Guard to shorten later appointment windows within acceptable limits so that a late start doesn’t force me to cancel."
Description

Recomputes subsequent appointment windows in real time to recover lost time by compressing within lender- and borrower-approved bounds. Considers travel-time estimates, lender availability, item prep/turnover buffers, borrower-preference thresholds, and HOA/organizer policies to produce feasible, conflict-free windows. Preserves minimum buffers and safety margins, surfaces updated ETAs, and updates the live calendar instantly. Degrades gracefully when full recovery is impossible by minimizing lateness and preserving highest-priority steps first.

Acceptance Criteria
Real-time Recompute After Delay Signal
Given an active chain with at least two remaining steps and a detected delay of 3 minutes or more on the current step When the engine receives the delay signal Then it recomputes windows for all remaining steps within 2 seconds And the recomputed plan contains no overlapping resource allocations And each window start and end is within lender- and borrower-approved bounds And travel-time estimates and prep/turnover buffers are satisfied And the chain deadline is met if any feasible plan exists that meets it
Buffers and Safety Margins Preserved
Given a baseline plan with minBufferMinutes and safetyMarginMinutes configured When recomputation occurs Then every adjacent pair of steps maintains at least minBufferMinutes between end and next start And pickup and drop-off windows include at least safetyMarginMinutes at both edges And if preservation of buffers makes the plan infeasible, the engine does not violate these buffers and flags the plan for degradation instead
Priority-Aware Degradation When Recovery Is Impossible
Given constraints render on-time completion infeasible When degradation mode is engaged Then the engine chooses a plan that minimizes the sum of lateness across remaining steps And no High-priority step is delayed if there exists any feasible plan that delays only lower-priority steps And any lateness on High-priority steps is less than or equal to lateness on Medium/Low when trade-offs are required And updated ETAs and lateness deltas are surfaced on each remaining step
Live Calendar and ETA Synchronization
Given a recomputed plan is produced When the plan is committed Then all affected calendar entries are updated within 1 second And each entry displays the new window and ETA And obsolete entries are versioned and marked as superseded And no stale plan version overwrites a newer one
Constraint Compliance: Availability, Policies, Preferences, Buffers
Rule: Recomputed windows must lie within lender availability windows. Rule: No recomputed window may intersect HOA/organizer blackout periods or outside permitted hours. Rule: Borrower minimum-notice thresholds must be respected when advancing any step; steps may be delayed beyond preference but not advanced earlier than allowed. Rule: Item prep/turnover buffers between consecutive bookings must be maintained. Rule: Per-step compression must not exceed the configured maximum compression percentage for both borrower and lender; the stricter limit applies.
Step Reordering to Recover Time Without Conflicts
Given steps marked reorderable with precedence constraints and shared resources When recomputation occurs Then the engine may reorder only steps marked reorderable And all precedence constraints are satisfied And no resource (lender, location, item) is double-booked at any time And travel-time feasibility is maintained for each transition And the resulting schedule's total projected lateness is less than or equal to the original order
Constraint-based Step Reordering
"As a borrower with multiple pickups, I want the system to rearrange the order to make up time so that I can still finish before my deadline."
Description

Automatically reorders independent pickups/returns to reduce total delay while honoring hard constraints (dependencies, lender blackout times, deposit requirements, item readiness, maximum detour distance) and soft preferences (geographic clustering, user-set priorities). Uses a constraint solver to evaluate alternatives, locks dependent sequences, and selects the best plan that restores on-time completion. Emits a clear plan diff with rationale and applies changes to the user’s itinerary and lender calendars.

Acceptance Criteria
Dependency Preservation During Reordering
Given an itinerary containing dependent steps and independent steps And a delay is detected on one step When the constraint solver generates a new sequence Then no dependent sequence order is violated And only independent steps are reordered relative to each other And the output includes a list of steps locked due to dependencies
Respect Lender Availability and Blackout Windows
Given each lender provides availability windows and blackout periods for items When new times are proposed by the solver Then every adjusted pickup/return falls within an allowed availability window And no step overlaps a lender blackout period And steps without a compliant time are left unchanged and flagged as constraints preventing reordering
Deposit Validity and Item Readiness Honored
Given some items require a deposit hold with an expiration timestamp and have readiness times When a step involving those items is moved Then the deposit hold remains valid through the new start time or is extended successfully before applying changes And the item readiness time is earlier than or equal to the new start time And if either condition cannot be met, the step is excluded from reordering and the reason is recorded
Maximum Detour Limit Enforcement
Given the user has configured a maximum additional travel distance or time for Drift Guard When the solver proposes a reordered route Then the total added travel distance or time compared to the baseline plan does not exceed the configured maximum And no individual leg exceeds any configured per-leg detour limit
Soft Preferences: User Priorities and Geographic Clustering
Given user-set item priorities and a preference for geographic clustering And multiple feasible reorderings satisfy all hard constraints When selecting the final plan Then the chosen plan maximizes the weighted score for user priorities and geographic clustering And the plan diff includes the selected plan’s soft-score and the primary reasons (e.g., priority preference, cluster proximity)
Optimal Plan Selection and Deadline Recovery
Given the itinerary has a defined completion deadline And a step delay triggers reordering When the solver evaluates alternatives Then it returns a plan that meets the deadline if any feasible plan exists And if no plan can meet the deadline, it returns the plan with minimal lateness and reports the lateness in minutes And the solver completes within 3 seconds for itineraries up to 20 steps
Plan Diff, Calendar Application, and Notifications
Given a reordered plan is selected When changes are applied Then a plan diff is emitted showing before/after times, moved steps, and rationale tags for each change And the user itinerary is updated and synchronized And lender calendars are updated via API without creating conflicts And notifications are sent to the user and all affected lenders summarizing changes and reasons And any failed external update is surfaced with a clear error and the plan reflects the final applied state
Lender Auto-Notify & Consent Workflow
"As a lender, I want clear adjustment requests with simple approval options so that my availability is respected while helping the borrower stay on track."
Description

Notifies affected lenders when windows compress or reorder, providing proposed new times, impact, and one-tap approve/decline options via push, SMS, or email. Applies lender-specific tolerances for auto-accept within set thresholds; escalates for consent when exceeding them. On decline, suggests nearest feasible alternatives and coordinates across multiple lenders to converge on a viable plan. Synchronizes approvals back to the borrower’s timeline and updates the live calendar to keep all parties aligned.

Acceptance Criteria
Real-time Drift Notification via Preferred Channels
Given a borrower chain adjustment compresses or reorders a booking affecting Lender A And Lender A has a channel preference order of push > SMS > email When Drift Guard computes proposed new time windows Then the system sends the consent request within 30 seconds via the highest-ranked available channel And includes the proposed new pickup/return times in Lender A's local timezone, the delta from original, the reason for change, and one-tap Approve and Decline actions And if no interaction or delivery confirmation occurs within 2 minutes, the system retries via the next preferred channel And the lender receives no more than 2 notifications for the same adjustment
Auto-Accept Within Lender Tolerances
Given Lender B has auto-accept tolerance set to allow compressions up to 15 minutes and disallow reorders And a proposed change compresses the window by 10 minutes without reordering When Drift Guard prepares the notification Then the system auto-accepts the change without requesting explicit consent And records the auto-accept with timestamp, tolerance rule identifier, and actor=system And sends a confirmation notification to Lender B and updates the borrower timeline
Consent Escalation When Changes Exceed Tolerances
Given Lender C allows up to 10 minutes compression and permits reorders And a proposed change compresses the window by 25 minutes When Drift Guard prepares the notification Then the system requests explicit consent from Lender C via their preferred channel And Approve applies the change and records consent with timestamp and channel And Decline blocks the change and triggers the alternative proposal flow
Decline Resolution with Coordinated Alternative Proposals
Given a proposed change requires consent from multiple lenders (Lender D and Lender E) and Lender D declines When Drift Guard generates alternatives Then at least 2 feasible alternative plans are produced that satisfy item availability, travel time constraints, and all lender tolerances And the alternatives are sent to affected lenders and the borrower for selection and consent And upon borrower selection and all required approvals, the system updates the chain and cancels superseded holds And if no feasible plan exists, the borrower is notified with reasons and suggested next actions
Secure One-Tap Approve/Decline Links
Given a consent request is delivered via push, SMS, or email When the lender taps Approve or Decline Then the action is executed using a signed, single-use token that expires in 24 hours or when superseded And no login is required; multiple taps are idempotent and reflect the final state And the lender sees an immediate confirmation and a summary of the resulting schedule
Synchronized Timeline and Live Calendar Updates
Given changes are approved either explicitly or via auto-accept When the final required consent is recorded Then the borrower timeline and live calendar for all affected parties update within 15 seconds And all views (web and mobile) display consistent updated times and statuses And an audit log entry captures before/after times, consenting parties, and notification channels
Policy & Payments Consistency Alignment
"As an organizer, I want deposit holds and no-show policies to adapt correctly when schedules shift so that we remain fair and protected without manual work."
Description

Keeps Stripe deposit holds, no-show fees, and cancellation policies consistent when Drift Guard adjusts schedules. Extends or shortens deposit authorization windows as needed, ensures idempotent updates to payment intents, and prevents penalties when system-driven changes occur within policy. Logs all changes for dispute resolution, updates receipts and terms shown to users, and confirms policy impacts to organizers to preserve trust and compliance.

Acceptance Criteria
Deposit Hold Extends with Drift Guard Delay
Given a booking with an active deposit authorization and Drift Guard extends the return deadline When the new schedule is committed Then the deposit hold expiration is extended to cover the new return deadline plus a 2-hour buffer, within processor limits And the payment object update succeeds and is persisted to the booking record And the borrower-facing booking details show the updated deposit hold end time within 30 seconds
Seamless Re-Authorization Without Double Hold
Given an extension requires an authorization period beyond processor limits When re-authorization is required Then a new authorization is created at least 10 minutes before the old one expires And the old authorization is canceled within 5 minutes after the new authorization is confirmed And at no time does the concurrently held amount exceed the intended deposit for longer than 5 minutes And receipts display a single continuous hold with linked payment IDs in the audit log
Shortened Window Releases or Reduces Hold
Given Drift Guard shortens the borrowing window or the item is returned early with no charges due When the change is committed Then the deposit hold expiration is recalculated to at most 2 hours after the new return time And if the item is already returned and no charges are due, the authorization is released within 15 minutes And updated receipts reflect the earlier release time
Idempotent Payment Updates Across Multiple Adjustments
Given multiple Drift Guard schedule adjustments occur within the same booking When payment and policy objects are updated Then updates are idempotent using a deterministic idempotency key per booking and adjustment version And no duplicate authorizations or payment intents are created And after N rapid adjustments (N >= 5) only one active authorization exists with metadata reflecting the final schedule And API retries do not create additional holds
No Penalties on System-Driven Changes Within Policy
Given a schedule shift is initiated by Drift Guard and remains within defined cancellation/no-show grace rules When penalties are evaluated Then no cancellation or no-show fee is applied to the borrower And any pending penalty flags on the booking are cleared And user notifications explicitly state no penalty due to a system-driven adjustment And the audit log records reason_code=system_adjustment_no_penalty
Immutable Change Log for Disputes
Given any schedule or policy change affecting payments or fees When the change is saved Then an immutable log entry is written capturing booking_id, actor, reason_code, previous/new schedule times, previous/new policy windows, payment object IDs, and UTC timestamps And a hash/signature is stored to detect tampering And organizers and admins can retrieve the log within 2 seconds via UI/API And PII is redacted per policy while preserving traceability
Receipts, Terms, and Organizer Confirmation
Given a schedule change alters deposit hold duration or penalty windows When the change is committed Then in-app receipts, emails, and on-screen terms update within 60 seconds to reflect the new durations, amounts, and effective terms version And borrowers see a summary of changes with before/after times And organizers receive a policy impact banner requiring acknowledgment with a deep link to the audit log And the acknowledgment status is recorded and visible on the booking timeline
Borrower Controls, Overrides, and Locking
"As a borrower, I want to approve or tweak Drift Guard’s adjustments so that the plan reflects my preferences without breaking commitments."
Description

Provides the borrower with transparent controls to accept the suggested plan, lock specific steps, set maximum compression thresholds, opt out per booking, and manually nudge times within constraints. Shows a visual timeline of changes, ETA impacts, lender confirmations, and policy effects before applying. Supports undo/rollback, records override reasons for analytics, and safeguards against changes that would violate dependencies or lender limits.

Acceptance Criteria
Pre-Apply Change Preview for Plan Adjustments
Given a borrower has a booking with Drift Guard and pending schedule adjustments (auto-suggested or manual), When the borrower clicks Review Changes, Then a preview panel displays: a before/after visual timeline with step start/end times and diffs; overall ETA impact in minutes; per-step compression percentage and any reordering; lender confirmation status per affected step (confirmed/pending/unavailable); and policy effects (fees, penalties, deposit/hold changes, buffers). And Then Apply and Cancel controls are visible. And Then no schedule data is persisted until Apply is confirmed. And Then Cancel closes the preview and leaves the plan unchanged.
Accept Suggested Plan
Given Drift Guard proposes an updated plan and the borrower has no blocking validation errors, When the borrower confirms by clicking Apply on the preview, Then all suggested changes are applied to the booking and reflected on the timeline within the session. And Then affected lenders receive the appropriate confirmation/notification requests. And Then a success message is shown and the change is logged with action type=accept_suggested, user, timestamp, and diff payload.
Lock Steps Against Auto-Adjustment
Given a borrower views the step list for a booking, When the borrower toggles Lock on one or more steps, Then Drift Guard must not change the start/end times or reorder any locked step during auto-adjustments. And Then locked steps are visually marked and appear in a Locked filter. And Then if a drift would require moving a locked step to meet the overall deadline, the system presents alternatives that avoid moving the locked step and flags the plan as Unsatisfied if none exist. And Then the borrower can unlock a step to restore auto-adjustment eligibility, with the change logged.
Borrower Drift Guard Preferences per Booking
Given a borrower opens Booking Settings for Drift Guard, When the borrower sets a maximum compression threshold (percentage) within the system-configured range and saves, Then auto-compression on any step is capped at that threshold and the cap is displayed in previews and applied plans. And When the borrower opts out of Drift Guard for this booking and saves, Then no auto reordering or compression occurs for the booking while opt-out is active, and the plan is labeled Drift Guard Off. And Then preference changes take effect for subsequent suggestions and are recorded with user, timestamp, and values changed.
Manual Nudge with Constraint Validation and Undo
Given a borrower drags a step on the timeline or edits its time within the editor, When the new time respects all constraints (dependencies, lender limits, buffers, compression cap), Then the UI shows real-time validity, recalculates ETA impact, and enables Apply in the preview. And When the new time would violate a constraint, Then the UI blocks the change and displays the specific violated rule with guidance. And When a manual nudge is applied, Then an Undo option appears and reverts the last change within the current session, restoring the prior state and timeline, and logging an undo event with the reversed diff. And Then Redo is available after an undo within the same session.
Override Actions Require Reason and Audit Trail
Given a borrower initiates an override action (lock/unlock step, change compression threshold, opt-out/in of Drift Guard, manual nudge deviating from the suggested plan), When the borrower proceeds to Apply the change, Then the system requires selection of a reason (from a configurable list or free-text) before enabling Apply. And Then the applied change is recorded with reason, action type, user, timestamp, booking ID, affected steps, and before/after values for analytics. And Then reasons are queryable via analytics/export endpoints.
Safeguards Against Dependency and Lender Limit Violations
Given system constraints exist for each step (precedence/dependencies, lender availability windows, minimum notice, buffers, max overlaps), When an auto-suggested change or borrower override would violate any constraint, Then Apply is disabled and the preview lists the exact violated constraint per step. And Then the system suggests the nearest valid alternatives (up to N options) when available. And Then no violating change is persisted or sent to lenders. And Then if lender confirmation is required for a borderline case, the plan is held in Pending Confirmation and does not commit until confirmation is received.
Failure Handling & Escalation Paths
"As a borrower, I want actionable alternatives when catching up is impossible so that I can still achieve my goal with minimal hassle."
Description

When on-time completion is impossible, proposes recovery options such as extending deadlines with lender consent, substituting equivalent items/lenders, splitting the chain into multiple sessions, or rescheduling impacted steps. Quantifies time and cost trade-offs, coordinates approvals, and triggers organizer support for high-value or high-risk bookings. Communicates outcomes clearly to all parties and updates the live calendar and payment holds accordingly.

Acceptance Criteria
Auto-Proposed Recovery Options When Deadline Becomes Unachievable
Given a chain’s projected completion time exceeds the borrower’s deadline by any amount When Drift Guard recalculates after a delay or slip is detected Then the system presents at least three recovery options, including: (a) deadline extension pending lender consent, (b) equivalent item/lender substitution, and (c) rescheduling or splitting into multiple sessions And each option displays quantified impacts: new completion time, delta minutes vs. original, added/removed cost in the borrower’s currency, number of approvals required, and affected parties count And options are presented to the borrower within 30 seconds of detection And selecting an option creates pending approval tasks and a provisional calendar plan without committing changes until approvals complete
Lender Consent Workflow for Deadline Extension
Given the borrower selects a deadline-extension recovery option When lender consent is required for any affected time window Then the lender(s) receive actionable approval requests via their configured channels (in-app + email/SMS where enabled) within 10 seconds And each request includes: proposed new pickup/return time(s), reason for change, and any cost/deposit impact And the system records approve/decline with timestamp and actor, and auto-expires requests after 15 minutes with a decline outcome And upon full consent the plan is committed; upon any decline or timeout the next-best recovery option is auto-proposed within 10 seconds
Equivalent Item/Lender Substitution With Constraints
Given substitution is selected or required because the original item/lender is unavailable When searching the inventory for equivalents Then only items meeting required attributes (category, core specs, compatibility) and availability window are considered And candidates are ranked by earliest feasible completion, distance, reliability score, and borrower’s stated preferences And the top 3 candidates are presented with quantified time and cost deltas and any new approval requirements And upon borrower selection and required approvals, the live calendar updates the steps and Stripe deposit holds adjust to the new item’s policy without creating duplicate holds
Chain Split and Reschedule With Conflict Resolution
Given the chain cannot meet the deadline as a single session When Drift Guard proposes splitting into multiple sessions Then the resulting sessions have non-overlapping windows, honor minimum buffer/transit times, and maintain lender availability constraints And each session proposal includes final completion time, step count per session, and total added borrower trips And committing the split updates all impacted calendars, sends new ICS invites, and cancels superseded holds/appointments And if any session lacks required approvals, only that session remains pending while unaffected sessions are confirmed
High-Value/High-Risk Auto-Escalation to Organizer Support
Given a recovery path involves a booking with value ≥ configured threshold or a borrower risk score ≥ configured threshold When the recovery plan is generated Then a support case is auto-created and assigned to the organizer with severity based on value/risk And the organizer is notified in-app and via email within 2 minutes, with the proposed plan, trade-offs, and approval state And the case tracks SLA countdown and blocks commitment only if policy requires organizer approval; otherwise it proceeds while keeping support subscribed And all organizer actions are logged and visible in the booking audit trail
Calendar, Communications, and Payment Holds Synchronization
Given any recovery option is committed after required approvals When the plan transitions to committed state Then borrower and all affected lenders receive a single consolidated change summary including new times, costs, deposit holds, and who approved what And the live calendar reflects the new plan within 5 seconds, and obsolete events are canceled with reasons And Stripe deposit holds are re-authorized, increased, decreased, or released to match the new plan within 60 seconds; failures surface an actionable error and auto-roll back the plan to the last safe state And an immutable audit log entry captures the final state, notifications sent, and payment hold outcomes

Backup Shadow

Add risk-free contingency to critical steps with soft backup holds that auto-expire if unused. If your primary item falls through, the backup converts to a booking instantly, keeping momentum and preventing weekend derailments.

Requirements

Backup Hold Creation & Limits
"As a borrower, I want to add backup items to my booking so that if my first choice falls through I can still secure what I need without re-planning my weekend."
Description

Enable borrowers to attach one or more soft backup holds to a primary booking request for the same time window. A soft backup hold earmarks availability without fully blocking the item: lenders see a “shadow hold” status and can opt in/out at the item level. Configure system-wide and org-level limits (e.g., max 2 backups per booking, max hold duration), fairness rules to prevent hoarding, and visibility cues in search and item detail. Integrate with Sharehood’s smart pickup windows so backup holds inherit and display the same pickup/return constraints. Persist full audit trails and metrics for hold creation, reorder, cancellation, and expiry events.

Acceptance Criteria
Create Backup Holds on Primary Booking
Given a borrower has a primary booking request with a defined start and end time And the borrower is permitted to add backup holds When the borrower adds one or more items as backup holds for the same time window Then the system creates soft backup holds linked to the primary request and does not block those items from receiving other primary bookings And the lenders of those items see the status "Shadow Hold" with requester name and time window And search results and item detail pages display a "Shadow hold" badge yet remain bookable as primary by others And if a selected backup item’s time window does not exactly match the primary request window, the system prevents creation with the message "Backups must match primary time window" And a hold creation event is recorded with booking ID, item ID, user ID, timestamp, and source (web/mobile)
Enforce Max Backups per Booking (System and Org Limits)
Given a system default limit of 2 backups per booking and an org-level override of 1 for a borrower’s org When the borrower with one existing backup attempts to add a second backup Then the action is blocked with the message "Org limit reached: 1 backup per booking" and no additional hold is created And when a borrower without an org override has two backups and attempts a third Then the action is blocked with the message "Limit reached: max 2 backups per booking" And all limit checks are enforced server-side and reflected consistently in the UI within 1 second And a rejected-by-limit event is recorded with the violated rule and counts
Backup Hold Duration and Auto-Expiry
Given the max backup hold duration is configured to 12 hours When a backup hold reaches 12 hours without converting or being cancelled Then the hold auto-expires and is removed from the booking And the borrower and lender receive notifications within 60 seconds indicating expiry and reason "Duration exceeded" And the item immediately loses its "Shadow hold" badge in search and detail And an expiry event is logged with booking ID, item ID, user ID, timestamp, and duration at expiry
Lender Item Opt-in/Out Enforcement
Given a lender has opted out of accepting backup holds on Item D When any borrower attempts to add Item D as a backup hold Then the action is blocked with the message "Backups not accepted for this item" and no hold is created And search and item detail for Item D display a visible cue "Backups not accepted" And when the lender re-enables backups for Item D Then subsequent backup holds are allowed and appear to the lender as "Shadow Hold" without blocking other primary bookings And all opt-in/opt-out changes are audit logged with actor, timestamp, old/new value
Fairness Rules to Prevent Hoarding
Given a fairness rule of max 3 active backup holds per borrower per overlapping time window And a rule of max 1 backup hold per lender per booking When a borrower attempts to create a hold that would exceed either rule Then the action is blocked with a specific error naming the violated rule and the current count And attempts to create more than 3 overlapping backup holds across different items are prevented And within a single booking, attempts to add two backup holds from the same lender are prevented And violations are recorded with user ID, rule ID, and timestamp
Smart Pickup Window Inheritance
Given the primary booking request has smart pickup and return windows for the selected time period When a backup hold is created Then the backup hold inherits and displays the same pickup and return windows on borrower and lender views And any auto-adjustment to the primary’s smart windows propagates to all active backup holds within 60 seconds and updates their displays And when a backup converts to a booking, the inherited smart windows are preserved without change
Reorder Priority of Backup Holds and Conversion Order
Given a booking has multiple backup holds with a defined priority order When the borrower reorders the backup list and saves Then the new order persists and is reflected in both borrower UI and lender notifications And if the primary booking fails, conversion attempts follow the updated priority order strictly (first to succeed converts; others auto-expire) And the reorder action is audit logged with old order, new order, actor, and timestamp
Auto-Expire Timers & Conditions
"As a lender, I want backup holds to expire automatically when they’re not needed so that my item returns to availability quickly and I don’t lose legitimate bookings."
Description

Implement deterministic timers and state conditions for backup holds to auto-expire when no longer needed. Backups should release immediately upon (a) successful confirmation and pickup of the primary booking, (b) lender decline of the backup, or (c) reaching a configurable cutoff before the start time (e.g., 2 hours pre-pickup) if not converted. Expiry must free calendar availability, release any pre-authorizations, notify parties, and record telemetry. Support per-organization overrides and guardrails to prevent premature expiry during active conversion workflows.

Acceptance Criteria
Primary Pickup Triggers Backup Expiry
Given a backup hold H associated to primary booking P for the same time window And P is in status=confirmed When P is marked picked_up (via QR scan or manual confirmation) at time tp Then H transitions to status=expired within 60 seconds of tp And the reserved time window is removed from the backup lender’s calendar and is available for new bookings And any payment pre-authorization linked to H is released And borrower and backup lender receive notifications within 60 seconds containing reason_code=primary_picked_up and hold_id And an expiry event is recorded with reason_code=primary_picked_up, hold_id, org_id, primary_booking_id=P.id, occurred_at_utc, and processing_latency_ms
Lender Declines Backup Hold
Given a backup hold H And the lender L of H declines the backup request When the decline action is saved Then H transitions to status=expired within 30 seconds And the held time window is freed on the lender’s calendar And any payment pre-authorization linked to H is released And borrower and lender receive notifications within 60 seconds containing reason_code=lender_declined and hold_id And an expiry event is recorded with reason_code=lender_declined, hold_id, org_id, occurred_at_utc, and processing_latency_ms
Cutoff Window Auto-Expiry
Given a backup hold H with start_time S And organization org has cutoff_before_start set to C (default 2h if not overridden) And H is not converted and H.conversion_in_progress=false When current_time reaches S - C Then H transitions to status=expired within 60 seconds And the held time window is freed on the lender’s calendar And any payment pre-authorization linked to H is released And borrower and lender receive notifications within 60 seconds containing reason_code=cutoff_elapsed and hold_id And an expiry event is recorded with reason_code=cutoff_elapsed, hold_id, org_id, occurred_at_utc, and processing_latency_ms
Calendar Availability Freed on Expiry
Given a backup hold H with reserved window W on item I When H expires for any reason Then I’s calendar shows W as available in owner and public booking views within 60 seconds And global search and availability APIs allow new bookings for I in W And the system prevents conversion of H after expiry (attempts return 409 Conflict with reason=already_expired) And an audit log entry links H to the availability change with timestamps (UTC)
Pre-Authorization Released on Expiry
Given a backup hold H with an active payment pre-authorization A When H expires for any reason Then the system calls the PSP to reverse A immediately and marks A.status=released within 60 seconds of a successful PSP response And the release operation is idempotent; repeated expiry signals do not create duplicate requests or errors And on transient failure, the system retries with exponential backoff for up to 15 minutes and surfaces unresolved failures to operations observability And no charge capture occurs for H after expiry
Telemetry Logged for Expiry Events
Given any expiry event E for hold H When H expires Then a telemetry record is written with fields: event_name=backup_hold_expired, hold_id, reason_code in {primary_picked_up, lender_declined, cutoff_elapsed}, org_id, lender_id, borrower_id, item_id, start_time_utc, end_time_utc, occurred_at_utc, processing_latency_ms, preauth_release_result And the telemetry record is queryable in analytics within 5 minutes And duplicate expiry triggers for the same H are de-duplicated via an idempotency key
Org Overrides and Conversion Guardrails
Given OrgA sets cutoff_before_start=C1 (e.g., 1h) and OrgB uses the default of 2h When backup holds are created under OrgA and OrgB Then auto-expiry uses C1 for OrgA and 2h for OrgB And borrower- or item-level settings cannot override the org-level cutoff unless explicitly enabled by an org policy flag And while H.conversion_in_progress=true, no auto-expiry is executed due to cutoff_elapsed or primary_picked_up; expiry is deferred until conversion completes (converted or aborted), after which expiry is re-evaluated And if lender_declined occurs during conversion, the conversion is aborted and H expires with reason_code=lender_declined And all state transitions are atomic and idempotent; concurrent triggers yield a single expiry outcome
Instant Failover Conversion
"As a borrower, I want my backup to become a confirmed booking automatically if the primary falls through so that my plans continue without manual scrambling."
Description

Provide an event-driven conversion engine that monitors the primary booking’s lifecycle and instantly converts the highest-priority viable backup into a confirmed booking when failure signals occur (e.g., owner cancellation, item suddenly unavailable, borrower-declined change, payment failure). Conversion must be atomic and idempotent: carry forward borrower profile, pricing, deposit terms, and smart pickup window; capture deposit; update calendars; and dispatch notifications. If conversion fails (e.g., payment capture error), automatically try the next backup in sequence and roll back partial state cleanly.

Acceptance Criteria
Failure Detection & Initiation SLA
- Given a confirmed primary booking with at least one active backup hold, When a failure signal occurs (owner cancellation, item unavailable, borrower-declined change, payment failure), Then a failover conversion attempt is initiated within 2 seconds of signal receipt. - Given multiple failure signals for the same booking within a 60-second window, When they are processed, Then only one failover conversion attempt is initiated for the booking. - Given no active backups exist, When a failure signal occurs, Then the system records the failure reason and does not initiate conversion, within 2 seconds.
Viable Backup Selection & Priority Order
- Given multiple backups sorted by priority with expiration timestamps, When failover starts, Then the system selects the highest-priority backup whose hold is unexpired, item is available for the required time window, borrower eligibility and deposit limit are satisfied, and price terms match the original agreement. - Given the top-priority backup is not viable, When selection runs, Then the next backup is evaluated in order until a viable one is found or the list is exhausted. - Given a backup is skipped, When selection completes, Then the skip reason is recorded (e.g., expired, unavailable, terms mismatch).
Atomic Conversion of Booking State
- Given a viable backup is selected, When conversion executes, Then the system atomically: creates one confirmed booking for the backup item, carries forward borrower profile and verified contact, applies the original pricing and deposit terms, sets the smart pickup window, captures the deposit via Stripe, updates calendars to booked, and stages notifications for dispatch. - Given any sub-step fails before commit, When conversion aborts, Then no booking is created, no calendar updates persist, and no deposit is captured.
Idempotent Processing & Duplicate Signal Handling
- Given the same failure event is received more than once or retried, When conversion is processed with the same idempotency key, Then no duplicate bookings or duplicate deposit captures are created, and the existing confirmed booking ID is returned. - Given parallel workers attempt conversion for the same booking, When concurrency control is applied, Then only one conversion may commit and others exit without side effects.
Sequential Retry with Clean Rollback
- Given conversion for the selected backup fails due to payment capture error or transient system error, When rollback completes, Then the next backup in priority order is attempted within 3 seconds. - Given all backups fail conversion, When retries finish, Then the system restores pre-failover state for calendars and holds, releases any partial authorizations, and marks the failover as unsuccessful with a final reason code.
Calendar & Smart Pickup Window Consistency
- Given a backup is converted, When calendars are updated, Then the backup item’s calendar shows the booking as confirmed and all other backup holds for the time window are released within 1 second. - Given the smart pickup window conflicts with existing commitments, When conversion commits, Then the window auto-adjusts per policy to a non-conflicting slot and the adjusted window is persisted on the booking. - Given conversion is rolled back, When state is restored, Then no lingering calendar blocks or backup holds remain.
Notifications & User Visibility
- Given a successful conversion, When notifications dispatch, Then the borrower and relevant owners receive messages within 5 seconds containing booking ID, item, pickup window, price, deposit amount, and next steps. - Given conversion fails for all backups, When notifications dispatch, Then the borrower receives a failure message with reason and suggested actions within 5 seconds. - Given a conversion occurred, When the borrower opens the app, Then the booking detail reflects the converted item and pickup window within 5 seconds and an activity entry records the failover event.
Calendar Soft-Block & Availability Logic
"As an organizer, I want clear visibility into how backup holds affect availability so that I can manage inventory and avoid conflicts across my neighborhood library."
Description

Extend the live calendar to represent backup holds as soft blocks that inform availability calculations without fully preventing other primary bookings. Design visual and API indicators for "shadow" status, ensure smart pickup windows adjust for overlapping soft and hard blocks, and prevent conflicts such as multiple backups on the same item and time slot. Organizer dashboards must summarize backup impact across inventories and provide filters to view, sort, and manage shadow holds at scale.

Acceptance Criteria
Calendar displays soft backup holds distinctly
Given an item with a confirmed primary booking and an overlapping backup (shadow) hold When the item calendar is viewed in web or mobile Then the shadow hold is rendered with a “Shadow” badge and semi-transparent style per design tokens And the primary booking remains full-opacity And the tooltip/popover shows type=Shadow, start/end, requester name, and autoExpireAt timestamp And the screen-reader label announces “Shadow hold” with dates And the events API includes fields: isShadow=true, status=soft_block, autoExpireAt, and holdId
Availability calculation respects soft blocks without fully blocking
Given a shadow hold overlaps a time window on an item When availability is queried via API or UI for that item Then the overlapping window remains discoverable for new primary bookings And smart pickup windows exclude hard booking overlaps but allow selection overlapping the shadow hold And the configured pickup/return buffer is applied only to hard bookings, not to shadow holds And the availability payload includes softBlockOverlapMinutes > 0 for affected windows And no hard-blocked time is returned as available
Auto-expire unused backup holds
Given a shadow hold has an autoExpireAt timestamp When current time >= autoExpireAt and the hold has not converted to a booking Then the hold status changes to expired and is removed from calendar views within 60 seconds And the availability API stops reporting the soft block within 60 seconds And the requester receives a notification that the backup expired And the time window becomes fully available for primary bookings
Prevent multiple backups on the same item and time slot
Given an item has an existing active shadow hold on a time window When a user attempts to create another shadow hold that overlaps the existing hold by any amount of time Then the request is rejected with HTTP 409 and errorCode=SHADOW_CONFLICT And the UI displays “Backup unavailable for this time window” And an audit log entry is created with actor, itemId, time window, and conflictHoldId
Instant conversion of backup to booking on primary failure
Given a shadow hold exists that corresponds to a primary booking for the same item and overlapping time When the primary booking is cancelled or marked no-show within the shadow hold window Then the shadow hold converts to a confirmed booking within 10 seconds And the borrower is notified and payment terms are applied per policy And calendar and API update to status=confirmed and isShadow=false with source=auto_converted And smart pickup windows recompute to reflect the new confirmed booking And the original primary booking is marked terminated with a terminal reason
Smart pickup windows adjust with mixed hard and soft overlaps
Given a user searches for pickup/return times on an item with overlapping hard booking(s) and a shadow hold When the system proposes pickup/return options Then options conflicting with hard bookings are not offered And options overlapping only with a shadow hold are offered with a non-blocking “may impact backup” warning And if the user confirms such an option, a primary booking is created and the overlapping shadow hold is auto-cancelled And the availability API exposes windowAdjustments with reasons [hard_block, soft_block] for each option
Organizer dashboard: shadow holds management and impact summary
Given an organizer manages at least 50 items with active shadow holds When they open the backup management view Then they can filter shadow holds by item, date range, status [active, converted, expired], and expiration <= next 24h And they can sort by expiration time, overlap minutes, and requester name And bulk actions support cancel, extend expiration (within policy), and notify borrower And the summary shows counts: active shadows, conversions (last 30 days), hours soft-blocked, conversion rate, and conflicts prevented And equivalent list, filter, sort, and bulk APIs are available with permission checks
Stripe Deposit Pre-Authorization for Backups
"As a borrower, I want deposits for backups to be handled automatically so that conversion is instant and I’m not charged unless a backup actually becomes my booking."
Description

Integrate with Stripe to create deposit pre-authorizations or SetupIntents for each backup that can be captured instantly on conversion without user input. Validate cumulative exposure across multiple backups against card limits to reduce declines; on conversion, capture the correct amount and void all unused authorizations. On expiry or cancellation, release holds promptly. Handle multi-merchant scenarios (different lenders) and edge cases (partial captures, 3DS challenges, capture timeouts) while remaining PCI and Stripe policy compliant.

Acceptance Criteria
Create Pre-Auth or SetupIntent Per Backup Without User Input on Conversion
- Given a borrower adds a backup with deposit amount D and a saved card, When they confirm the backup, Then the system creates a Stripe authorization hold for D (PaymentIntent with capture_method=manual or equivalent) or a SetupIntent tied to the customer and backup, and persists the Stripe IDs. - Given the hold is created, When inspecting Stripe, Then the PaymentIntent is in requires_capture with amount_capturable=D and is off_session=true. - Given the backup later converts, When capture is triggered server-side, Then the system captures without additional user input and receives a succeeded response within 2 seconds P95. - Rule: Idempotency keys are used for all create/confirm/capture operations; repeated requests do not create duplicate holds or captures. - Rule: No raw PAN/CVV/PII is stored or logged; only Stripe IDs/tokens are persisted.
Validate Cumulative Deposit Exposure Across Multiple Backups
- Given a borrower has N active backup holds on the same card totaling S, When creating an (N+1)th backup with deposit D, Then the system computes S+D and compares it to a configurable exposure ceiling E and proceeds only if S+D <= E. - Given Stripe declines the new authorization with insufficient_funds, When the decline occurs, Then the system cancels that new hold attempt, keeps prior holds intact, and surfaces a clear message with options to switch card, reduce backups, or change deposit. - Given a decline occurs mid-batch, When cleanup runs, Then no orphan holds are left open for the failed attempt. - Rule: Exposure checks occur atomically and are race-safe for concurrent backup actions.
Instant Conversion: Capture Matching Hold and Void Others
- Given a time slot’s backup converts to primary booking, When conversion starts, Then the system identifies the matching pre-authorization by backup ID and captures the exact deposit amount D within 2 seconds P95. - Given capture succeeds, When finalizing conversion, Then all other pre-authorizations for overlapping backups in that time window are voided within 5 seconds P95. - Rule: Exactly one capture is allowed per time slot; concurrent conversions use a distributed lock to prevent double-capture. - Rule: Borrower and lender receive success notifications with payment/capture identifiers.
Prompt Release on Backup Expiry or Cancellation
- Given a backup expires at its auto-expiry time or is canceled by the borrower, When the event fires, Then the system voids the associated authorization/SetupIntent within 60 seconds P95. - Given Stripe API is temporarily unavailable, When a void fails, Then the system retries with exponential backoff for up to 24 hours and flags for manual review if still not voided. - Rule: No backup hold remains open more than 10 minutes past expiry/cancellation in steady state.
Multi-Merchant Holds and Captures per Lender Account
- Given backups involve items from different lenders using Stripe Connect accounts, When creating holds, Then the system creates each hold under the correct connected account with accurate transfer_data/application_fee settings. - Given a backup converts, When capturing, Then only the hold on the winning lender’s account is captured; all others (across other connected accounts) are voided. - Rule: No funds are ever captured or transferred to the wrong connected account; accounting events reconcile 1:1 with Stripe logs.
3DS and SCA Handling for Backup Holds and Off-Session Capture
- Given a card requires 3DS for authorization, When creating the backup hold, Then the borrower is prompted to complete SCA once; on success, the payment method is set up for off_session capture. - Given the backup later converts, When capturing off_session, Then the capture succeeds without user input; if Stripe requests authentication, the system gracefully falls back to re-auth flow or re-authorizes with user consent. - Rule: SCA status and mandates are stored and reused to minimize user friction while remaining compliant.
Partial Capture and Idempotent Retry Handling
- Given a conversion requires capturing less than the authorized deposit, When capturing, Then the system captures the specified amount and automatically releases the remainder; Stripe reflects amount_captured=partial and no additional charges are created. - Given a network timeout or 5xx occurs during capture, When retrying with the same idempotency key, Then at most one capture occurs and the final state is consistent. - Rule: If the capture window is expired, the system re-authorizes and captures or fails gracefully with a clear message and no duplicate charges.
Backup UX & Notifications
"As a user, I want clear controls and timely notifications around my backups so that I understand their status and can adjust without confusion."
Description

Design intuitive UI flows to add, prioritize, and remove backups in one tap during checkout and from existing bookings. Display clear statuses (Primary, Backup 1/2), countdowns to auto-expiry, and conversion outcomes. Provide lenders with opt-in controls for accepting backup conversions automatically and configurable notification preferences. Deliver real-time push/SMS/email alerts for creation, expiry, conversion, and failures. Ensure accessibility, localization, and analytics instrumentation for funnel and cohort analysis.

Acceptance Criteria
One-Tap Backup Management at Checkout
Given a user is on checkout with a selected primary item and time window, When they tap "Add Backup" on an eligible alternative, Then a backup hold is created and labeled "Backup 1" within 1 second. Given one backup exists, When the user adds another eligible backup, Then it is labeled "Backup 2" and the UI prevents adding more than two backups. Given backups exist, When the user taps "Promote to Backup 1" on Backup 2, Then priorities swap and labels update within 1 second. Given a backup exists, When the user taps Remove and confirms, Then the backup hold is released and the card disappears within 1 second; on failure an error banner explains the issue and the backup remains unchanged.
Backup Management from Existing Booking
Given a user opens Booking Details for an active booking, When they tap "Add Backup", Then eligible alternatives are shown and upon selection a backup hold is created and displayed with label "Backup 1/2". Given backups exist on a booking, When the user reorders or removes them, Then changes persist and are reflected after app relaunch or page refresh. Given two backups already exist, When the user attempts to add another, Then the "Add Backup" action is disabled with helper text indicating the limit has been reached.
Status Badges, Countdown Timers, and Conversion Outcomes
Given a primary and backups are present, When the booking screen renders, Then each card shows a status badge: "Primary", "Backup 1", or "Backup 2". Given a backup hold has an expiry timestamp, When the screen is visible, Then a countdown timer displays time remaining with 1-second updates and drift < 1 second per minute. Given a backup converts, When conversion completes, Then the UI shows "Converted to Primary" with timestamp and the prior primary is marked accordingly. Given a backup expires unused, When expiry occurs, Then the UI shows "Expired" and removes interactive actions for that backup.
Auto-Expiry and Instant Conversion Behavior
Given the primary becomes unavailable before the borrow window, When lender auto-convert is enabled for the backup's listing, Then Backup 1 converts to a confirmed booking within 10 seconds and the borrower sees confirmation. Given lender auto-convert is not enabled, When the primary becomes unavailable, Then a conversion request is sent to the lender and the backup hold remains pending until approval or auto-expiry, whichever occurs first. Given a backup reaches its expiry time with no conversion, When expiry occurs, Then the hold is released and the UI updates status to "Expired" within 10 seconds. Given a conversion attempt fails, When conversion is triggered, Then the system rolls back to the previous state, marks the attempt as "Conversion failed", and notifies borrower and lender.
Lender Auto-Convert and Notification Preferences
Given a lender views Listing Settings, When they toggle "Auto-accept backup conversions", Then the setting persists and is applied to subsequent conversion events. Given a lender or borrower opens Notification Preferences, When they enable or disable push, SMS, or email for creation, expiry, conversion, or failure events, Then channel delivery respects the configured preferences. Given preferences are saved, When the user returns later, Then the last-saved values are displayed and can be edited again.
Real-Time Push/SMS/Email Notifications
Given a backup is created, expires, converts, or fails, When the event occurs, Then a notification is dispatched to the borrower and relevant lender via enabled channels with delivery targets: push ≤ 5 seconds, SMS ≤ 30 seconds, email ≤ 2 minutes. Given multiple state changes occur within 5 seconds, When notifications are generated, Then recipients receive a single deduplicated message summarizing the latest state. Given a notification contains a deep link, When the recipient taps or clicks it, Then the app or web opens directly to the relevant Booking Details or Notification Center item.
Accessibility, Localization, and Analytics Instrumentation
Given users rely on assistive technologies, When navigating backup management and status UIs, Then all actions are reachable via keyboard, focus order is logical, ARIA labels/roles announce status changes, and color contrast meets WCAG 2.1 AA. Given the app is set to any supported locale and script direction, When backup screens render, Then all strings are localized with correct pluralization, dates/times are formatted in the user's locale and time zone, and RTL layouts mirror appropriately without truncation. Given users interact with backup features, When key actions occur (create, remove, reorder, convert, expire, notification sent/delivered/opened), Then analytics events are captured with booking_id, backup_id, user_role, timestamp, locale, channel, and outcome, PII is not logged, and events are queryable in the analytics warehouse within 10 minutes for funnel and cohort analysis.

Template Kits

Start from proven project templates—like IKEA Build, Garden Bed, or Move Day—each with pre-set steps, recommended tools, and typical durations. Tailor to your space and skill level, then reserve the whole chain with one confirmation.

Requirements

Template Kit Catalog & Discovery
"As an urban resident, I want to browse proven project templates that fit my time, skill, and neighborhood so that I can quickly pick the right plan without researching tools and steps from scratch."
Description

Provide a browsable and searchable library of curated project templates (e.g., IKEA Build, Garden Bed, Move Day) with rich metadata including steps, recommended tools, typical durations, skill levels, and estimated total time/cost. Support filtering by dwelling type, skill level, available time window, and distance to lenders. Integrate with Sharehood’s inventory and calendar services to surface only templates that can be fulfilled within the user’s neighborhood and time constraints. Ensure templates display trust signals (ratings, completion counts) and organizer badges.

Acceptance Criteria
Keyword Search Within Neighborhood
Given the user’s neighborhood location is set and a distance radius is selected When the user enters a keyword (e.g., "IKEA") and submits search Then results include only templates whose title, tags, or description match the keyword And Then each returned template has at least one lender for every recommended tool within the selected distance radius And Then templates with zero local lender coverage for any required tool are excluded from results And Then the total results count equals the number of templates rendered
Multi-Filter Discovery by Dwelling, Skill, Time, and Distance
Given filters dwelling type=Apartment, skill level=Beginner, time window=Sat 9am–5pm (2-hour block), and distance ≤3 miles are applied When the user applies filters Then only templates requiring skill level ≤ Beginner are shown And Then only templates tagged for Apartment (or universally applicable) are shown And Then only templates for which the full tool chain can be scheduled within the specified time window are shown And Then only templates where all required tools have at least one lender within 3 miles are shown And Then active filters are visible and can be cleared individually or all at once
Fulfillable Chain Validation via Inventory and Calendar
Given a template with steps and required tools is evaluated When inventory and calendars for lenders within the user’s distance and time filters are checked Then the template is marked "Reservable" only if there exists at least one feasible schedule satisfying step durations and pickup/return buffers for all required tools And Then if not reservable, the template card displays "Not currently available" with a reason (e.g., missing tool, no overlapping availability) And Then the earliest feasible completion estimate is displayed on the card (e.g., "Completable Sat 2–6pm")
Template Detail Metadata Completeness and Estimates
Given a user opens a template detail page When the page loads Then it displays: ordered steps, recommended tools per step, typical duration per step, total estimated duration, required skill level, and estimated total cost And Then estimated total cost is computed from current lender rates for required tools within the selected distance; if multiple options exist, display a range with pricing basis And Then templates missing any required metadata cannot be published and are excluded from the catalog
Trust Signals and Organizer Badges Display
Given a template has ratings, completion counts, and organizer badge data When the template is shown in list and detail views Then the average rating (1–5), total completion count, and organizer badge are displayed consistently in both views And Then templates with insufficient ratings show "New" or "No ratings yet" instead of a numeric score And Then selecting the organizer badge opens the organizer profile with badge description
Empty-State Guidance and Alternatives
Given no templates satisfy the current search and filter criteria When results are fetched Then an empty-state message explains which constraint(s) failed (e.g., distance, time window, missing inventory) And Then the UI offers one-click suggestions to relax constraints (increase distance, expand time window, change date) and a Clear all option And Then at least three nearest-match templates are suggested that violate only one constraint, with the violated constraint labeled
Kit Customization Wizard
"As a DIYer with limited time, I want to tailor a template to my skill and schedule so that the plan matches my reality and I don’t overbook tools or time."
Description

Implement a guided flow that lets users tailor a chosen template to their space and skill: adjust step counts/durations, swap or remove steps, choose tool variants, and set preferred pickup/return windows. Validate feasibility in real time against inventory availability, organizer rules, and lender pickup hours. Allow saving drafts and personal templates for reuse. Persist customization as a structured plan that downstream services (calendar, deposits, notifications) can consume.

Acceptance Criteria
Edit Steps: Adjust Counts and Durations
Given a user has selected a template kit When the user changes a step duration Then the total project duration recalculates immediately and displays updated start/end estimates And organizer-defined min/max duration constraints are enforced with inline validation messages When the user increases or decreases step count for a repeatable step Then the total duration updates accordingly and any dependent steps shift relative timing And durations cannot be set below 1 minute or above 24 hours per step
Swap and Remove Steps with Dependency Validation
Given a template with steps including mandatory and dependent steps When the user attempts to remove a mandatory step Then the removal is blocked and a message cites the rule and lists dependent steps When the user removes a non-mandatory step Then the step is removed, downstream timings reflow, and the change is reflected in the summary When the user reorders steps via drag-and-drop Then dependency violations are prevented with real-time visual indicators and the drop is disallowed if invalid And an Undo control restores the last change within the current session
Select Tool Variants with Availability and Rules
Given a step that requires a tool with available variants When the user opens the tool variant selector Then only variants compatible with the selected step and user's skill level are selectable And each variant shows cost impact, required deposit, and earliest available window When the user selects an unavailable variant for the chosen window Then the wizard offers the next three available windows and up to three alternative variants that meet rules And deposit holds and total cost recalculate within 500 ms of selection
Set Pickup and Return Windows with Smart Adjustments
Given lender pickup hours and organizer blackout dates When the user selects preferred pickup and return windows Then the wizard validates against lender hours, inventory reservations, and organizer rules in real time And if a conflict exists, the system auto-adjusts to the nearest valid window and explains the adjustment When overlapping reservations are detected across steps Then the system staggers windows to prevent conflicts and preserves step order And all displayed times respect the user's timezone and daylight saving rules
Real-time Feasibility Validation and Feedback
Given the user modifies any step, tool, or time When the feasibility check runs Then validation feedback (success or error with reason code) appears within 800 ms And the Confirm Reservation action is disabled while any blocking errors exist When inventory, lender hours, or rules change server-side Then the wizard receives an update and revalidates within 5 seconds, notifying the user of changes
Save Drafts and Personal Templates
Given a user is authenticated When the user makes changes in the wizard Then a draft autosaves within 2 seconds of the last change and shows a Saved indicator with timestamp When the user explicitly saves as a personal template Then the system requires a unique name, stores a versioned template, and makes it available in the user's template list across devices And personal templates can be renamed, duplicated, or deleted with confirmation prompts When the user resumes a draft Then the wizard restores all edits, selections, and feasibility state from the last successful autosave
Persist Structured Plan and Trigger Downstream Services
Given the user confirms the customized kit When the system persists the plan Then it stores a structured plan record with step list, durations, selected variants, pickup/return windows, total cost, deposit hold amount, and policy references And it creates calendar reservations, places a Stripe deposit hold, and schedules notifications according to the plan And the operation is idempotent using a client-provided request ID, preventing duplicate holds or reservations on retries When any downstream action fails Then the system rolls back partial changes, surfaces an error with a correlation ID, and leaves the draft intact
One-Confirm Bundle Reservation
"As a borrower, I want to reserve every tool and time slot for my project in one confirmation so that I’m guaranteed the full chain without piecemeal bookings or surprises."
Description

Enable atomic reservation of all tools and time slots required by a customized template via a single confirmation. Coordinate holds across multiple items and lenders, apply Stripe deposit holds per item and aggregate total, and ensure all-or-nothing booking with rollback on failure. Provide alternative suggestions (dates/items) when conflicts arise. Generate a consolidated itinerary with pickup/return windows and reminders, and record a single reservation ID for user support and auditing.

Acceptance Criteria
Atomic Bundle Reservation Across Multiple Items and Lenders
- Given a customized template requires multiple tools from different lenders, When the user confirms the bundle, Then the system reserves all required items for their specified durations atomically with a single action. - Given any individual item reservation fails due to last‑minute unavailability, When the system attempts to book the bundle, Then no items are reserved and the user sees a single error indicating which items caused the failure. - Given the bundle is successfully booked, Then each lender’s calendar reflects the corresponding reservations and the user sees one confirmation for the entire bundle. - Given the reservation completes, Then the user’s booking is timestamped and associated to their account with the selected template variant and customization parameters.
Rollback on Partial Failure with Transactional Consistency
- Given at least one item becomes unavailable during booking, When the booking engine detects a failure, Then all provisional holds/locks for other items are released within 2 seconds. - Given a transient service error occurs (e.g., lender API timeout), When automatic retries are performed (up to 2 retries with exponential backoff up to 5 seconds), Then the booking either completes atomically or fully rolls back. - Given a rollback occurs, Then no item remains reserved, no reminders are scheduled, and any captured pre-authorizations are voided. - Given a rollback occurs, Then the user is shown a single failure message with a correlation ID and reason codes for each failed item.
Stripe Deposit Holds Per Item and Aggregate Total
- Given a bundle with multiple items each requiring a deposit, When the user confirms, Then separate Stripe authorization holds are created per item and an aggregate total is displayed to the user. - Given any item’s hold authorization fails, Then the entire booking fails and all other holds are immediately voided. - Given the booking succeeds, Then hold expiration times are set per-item according to policy and are visible in the itinerary and receipts. - Given the user cancels before pickup within free-cancelation policy, When the cancellation is processed, Then all holds are released within 10 minutes and reflected in Stripe and the user’s payment history.
Alternative Suggestions When Conflicts Prevent Atomic Booking
- Given at least one required item or time slot is unavailable, When atomic booking fails, Then the system returns at least three alternatives: (a) next available date/time preserving task order, (b) substitute items of equivalent specs, (c) mixed option minimizing total shift. - Given the user selects an alternative, When the system recalculates the chain, Then updated durations, availability, and deposits are shown with a one-click reconfirm action. - Given no viable alternatives exist within ±7 days, Then the user is informed and may set an availability alert or request organizer assistance.
Consolidated Itinerary With Smart Pickup/Return Windows and Reminders
- Given a successful bundle booking, Then a single itinerary is generated showing per-item pickup/return windows that auto-adjust to avoid overlaps and include a default 15-minute buffer for travel between locations. - Given lenders have differing pickup hours and constraints, When generating the itinerary, Then all windows respect each lender’s availability and the user’s time zone. - Given the itinerary is finalized, Then reminders are scheduled: T-24h and T-2h before first pickup, and T+1h before the first return window closes, delivered via in-app and email. - Given any item’s window changes due to lender updates, When recalculation occurs, Then the user is notified and the itinerary rebalances to maintain non-overlapping windows or prompts for rebooking if impossible.
Single Reservation ID and Unified Audit Trail
- Given a successful booking, Then a single Reservation ID (UUID) is generated that links all item reservations, deposit holds, reminders, and itinerary artifacts. - Given the user or support agent searches by Reservation ID, Then the full audit trail (timestamps, item IDs/SKUs, lender IDs, pricing, hold statuses, notifications) is retrievable within 2 seconds. - Given data retention policy of 24 months, Then the audit record persists for that period unless placed on legal hold. - Given the booking is modified (e.g., alternative accepted), Then the same Reservation ID is retained with versioned audit entries capturing the change.
Concurrency Control and Idempotency for Simultaneous Requests
- Given two users attempt to book overlapping bundles involving the same item within 500 ms, When the system processes the requests, Then only one succeeds and the other receives a clear conflict message without any holds captured. - Given a user resubmits the confirmation due to a network retry within 60 seconds, When an idempotency key is reused, Then only one booking is created and duplicate side effects (holds, reminders) do not occur. - Given the system is under load (p95 booking latency target ≤ 800 ms), Then atomicity and ordering guarantees are preserved and no partial reservations or orphaned holds remain. - Given deadlock or contention is detected during booking, Then the system aborts and retries the transaction once; if it still fails, the user receives a failure with alternative suggestions.
Smart Duration & Calendar Integration
"As a time-constrained user, I want the template schedule to auto-adjust around real pickup windows and conflicts so that my plan stays realistic without manual rescheduling."
Description

Leverage template step durations and user inputs (skill, transport mode, distance) to compute a realistic schedule, adding buffers for pickup/return and lender handoff windows. Auto-adjust for overlaps using Sharehood’s live calendar logic and reflow steps when conflicts or delays occur. Sync schedule to the user’s device calendar and send proactive notifications when a shift is needed, requesting quick confirmations to keep reservations valid.

Acceptance Criteria
Compute Schedule From Template and User Inputs
Given a selected template with predefined step durations and user inputs for skill level, transport mode, and distance, When the user taps Plan Schedule, Then the system computes start/end times per step using configured multipliers (default skill multipliers: Novice 1.25, Intermediate 1.0, Expert 0.85) and transport speeds (default Walk 5 km/h, Bike 15 km/h, Car 30 km/h), and displays total projected duration. Given required inputs are incomplete or invalid, When the user attempts to plan, Then an inline validation message identifies missing fields and the Confirm button is disabled until resolved. Given a template up to 25 steps, When scheduling is executed, Then the computation completes in under 2 seconds on a standard device and displays without a full page reload. Given the user’s device timezone, When times are displayed or synced, Then all timestamps use the user’s timezone and include daylight saving adjustments.
Apply Pickup/Return Buffers and Handoff Windows
Given lender-defined pickup/return buffers (default 15 minutes) and handoff windows, When generating the schedule, Then buffer blocks are inserted before pickups and after returns and are visible as labeled slots in the timeline. Given multiple lenders with distinct availability windows, When steps require items from different lenders, Then each step is placed within the respective lender’s open window; if infeasible, the system surfaces a conflict message naming the blocking item and time window. Given buffers and step durations, When adjacent steps are placed, Then a minimum 5-minute separation is maintained; overlapping steps are not permitted in the final schedule.
Auto-Resolve Calendar Overlaps and Reflow
Given the live calendar reveals an overlap with existing reservations, When the user taps Confirm Chain, Then the system reflows steps to the earliest conflict-free slots while preserving step order, dependencies, durations, and buffers. Given no conflict-free arrangement exists within ±48 hours of the original start, When reflow is attempted, Then the system offers at least three alternative start options and highlights affected steps. Given a lender delay update shifts an item’s availability by X minutes, When the platform receives the update, Then downstream dependent steps are shifted accordingly and the user is notified of the new schedule within 60 seconds.
Two-Way Device Calendar Sync
Given the user authorizes calendar access, When the schedule is confirmed, Then calendar events are created for each step (with item, location, lender, and buffer labels) plus a parent project event, all in the user’s device calendar (Google, Apple, Outlook via ICS). Given calendar events exist, When the Sharehood schedule is changed (time shift, add, cancel), Then corresponding calendar events are updated or removed within 60 seconds using stable UIDs (no duplicate events). Given the user revokes calendar permissions, When a subsequent change occurs, Then no further calendar updates are pushed and the user is prompted to manually resubscribe if desired.
Proactive Shift Notifications and Quick Confirmations
Given a schedule shift greater than 5 minutes is detected due to conflicts or delays, When the change is computed, Then the user receives an in-app and push notification within 60 seconds containing the new times and two actions: Accept and Propose Alternate. Given notifications are sent, When no user response is received within 15 minutes, Then an escalation is sent via SMS and/or email if the user has those channels enabled. Given the user taps Accept, When confirmation is received, Then reservations are retained without lapse and all affected lenders receive updated times. Given the user taps Propose Alternate, When the flow opens, Then at least three alternative windows are offered and soft holds are extended by 10 minutes pending selection.
Reservation Validity During Pending Confirmations
Given reflow requires user confirmation, When the updated plan is presented, Then item reservations remain soft-held for 15 minutes with a visible countdown; after timeout, availability is released and the user is notified. Given the user accepts within the soft-hold window, When confirmation is processed, Then all step reservations transition to firm status and their time blocks lock on the live calendar. Given no response after two escalation attempts, When the soft-hold window expires, Then the entire chain is auto-cancelled and any associated calendar events are removed from the user’s device.
Recommended Tools Mapping & Substitutions
"As a borrower, I want recommended tools auto-selected with smart substitutions when needed so that I can complete the project even if the ideal items aren’t available nearby."
Description

Map each template step to specific tool SKUs available in the neighborhood, preferring organizer-curated items. When exact matches are unavailable, suggest compatible substitutes with clear trade-offs (cost, deposit, performance) and update durations if substitutes affect pace. Validate quantity and concurrency needs across steps. Show distance and pickup compatibility, and lock final selections for reservation.

Acceptance Criteria
Step-to-SKU Mapping Prioritizing Curated Tools
Given a selected template kit with defined steps, When SKU mapping runs, Then each step is assigned at least one available neighborhood SKU that satisfies the step’s tool type and minimum performance requirements. Given a step has multiple matching SKUs, When ranking is applied, Then organizer-curated SKUs are ranked highest and preselected by default, with a visible “Organizer Pick” label. Given mapping completes, When the user reviews the template, Then 100% of steps display either a default SKU selection or a clearly indicated need for a substitute.
Compatible Substitute Suggestions with Trade-offs
Given a step lacks an exact matching SKU, When substitution logic executes, Then at least one compatible substitute is listed (if available) with displayed fields: rental cost per period, deposit hold amount, performance metrics, and a succinct trade-off note. Given multiple substitutes are available, When they are presented, Then they are sorted by lowest total cost (rental + fees) while meeting minimum performance, with the current default highlighted. Given a user selects a substitute with lower performance than the template baseline but above the minimum viable threshold, When selection is made, Then the system requires confirmation and flags that step duration will increase. Given no compatible substitutes exist, When mapping concludes, Then the step is flagged as “Unfillable” with actionable recommendations (expand radius, shift schedule, or request item).
Auto-adjust Step Durations Based on Selected Tools
Given a step has a baseline duration tied to a reference tool performance, When the user selects a tool with different performance, Then the step duration recalculates using the configured performance-to-duration model. Given one or more step durations change, When the schedule is recomputed, Then overall timeline and pickup windows update and maintain non-overlap and buffer constraints. Given recalculation causes the plan to exceed the user’s max day/time constraints, When detected, Then the system surfaces a blocking warning and suggests alternative tools or schedule adjustments.
Quantity and Concurrency Validation Across Steps
Given the template includes concurrent steps requiring the same tool type, When mapping runs, Then the system validates simultaneous quantity needs and assigns distinct SKUs to meet N required units without conflict. Given N units are required for a step, When reservation is generated, Then N individual SKUs are held for the exact overlapping time windows, including buffers. Given available quantity (including substitutes) is insufficient, When finalization is attempted, Then confirmation is blocked and options are offered: select different times, reduce concurrency, or adjust tool choices.
Distance and Pickup Window Compatibility
Given the user’s location and radius preferences, When SKUs are displayed, Then each SKU shows distance, pickup/delivery options, and pickup window compatibility status relative to the computed schedule. Given a SKU’s pickup window conflicts with the planned start or return times, When selections are auto-applied, Then the conflicting SKU is excluded from default selection and marked with a conflict badge if shown. Given multiple selected SKUs require pickups at different locations with overlapping windows, When the itinerary is generated, Then the system proposes an adjusted pickup sequence or schedule shift to keep all pickups feasible.
Locking Final Selections for Unified Reservation
Given the user confirms tool selections, When they submit the reservation, Then the system locks selected SKUs, associated durations, and pickup windows, and generates a single confirmation covering all steps. Given items are locked, When another user attempts an overlapping booking on the same SKUs, Then the system prevents double-booking and surfaces unavailability. Given a user edits locked selections, When changes are saved, Then Stripe deposit holds and durations are recalculated, conflicts are revalidated, and a new confirmation version is issued.
No-Match Fallback and Recovery
Given neither matches nor compatible substitutes exist within the set radius, When mapping completes, Then the system marks affected steps as “Unfillable,” blocks reservation, and presents actionable recovery options (expand radius, shift dates, notify organizer). Given the user expands the search radius or shifts schedule, When remapping runs, Then newly eligible SKUs are included and step status updates accordingly. Given recovery attempts fail to find valid options, When the user exits, Then no holds are placed and the draft plan is saved with unresolved steps clearly indicated.
Step-by-Step Guidance & Progress Tracking
"As a user executing my project, I want step-by-step guidance with timers and reminders so that I stay on track and return items on time without missing steps."
Description

Provide an in-app execution mode for the reserved template: checklists per step, how-to media, safety notes, timers, and completion tracking. Support offline access for instructions, and prompt users when it’s time to pick up/return items based on the live schedule. Capture actual durations and deviations to refine future estimates and template quality. Allow marking steps as blocked to trigger reschedule suggestions.

Acceptance Criteria
In-App Execution Mode: Checklist, Media, Safety Notes
Given a user has an active reservation for a Template Kit When they open Execution Mode from the booking Then the template displays as an ordered list of steps with per-step checklists, how-to media, and safety notes Given a step has checklist items When the user marks items complete Then the step shows item-level completion counts and prevents marking the step done until all required items are checked or the user explicitly confirms Skip Given a step includes safety notes When the user attempts to start the step Then the safety notes are shown and must be acknowledged once per device session before starting timers Given a step has how-to media When the user taps a media item Then it opens inline and is playable with play, pause, and seek controls Given a multi-step template When the user completes a step Then the next step is automatically focused and the overall progress indicator updates as a percentage
Offline Access to Step Instructions
Given the user is online and views a reserved template When they select Download for Offline Then all step text, images, and videos are cached to device storage and a download complete confirmation is shown Given the device is offline When the user opens Execution Mode for a previously downloaded template Then all step instructions (text/images/video) load without network calls or error messages Given the device reconnects after offline usage When unsynced changes exist (progress, notes, durations) Then the app syncs them within 30 seconds and displays a visible sync status that resolves to Up to date Given device storage becomes insufficient during download When caching fails Then the app informs the user of insufficient space, preserves already cached assets, and allows retry after freeing space
Step Timers and Actual Duration Capture
Given a step is ready to begin When the user taps Start Timer Then a running timer appears and counts in real time with accuracy within ±1 second per minute Given a step timer is running When the user pauses and later resumes Then elapsed time excludes paused intervals and is displayed continuously Given a step is completed When the timer is running Then the timer stops automatically and the actual duration is saved with the step Given a user completes a step without starting a timer When completion is confirmed Then the app prompts for manual duration entry (HH:MM) before saving Given a template session has multiple steps When all steps have actual durations Then the total actual duration equals the sum of step actuals and is shown in the session summary
Schedule-Based Pickup and Return Prompts
Given a confirmed booking with live pickup and return windows When the time is 15 minutes before the pickup window Then the user receives a notification and in-app banner containing pickup location and window details Given the pickup window starts and the item is not yet marked picked up When the window start time is reached Then a second prompt is delivered with a direct Open Booking CTA Given the return window is 30 minutes away When the time reaches T-30 minutes Then the user receives a return reminder notification and in-app banner Given the user taps the prompt CTA When navigation occurs Then the booking details open with map/location and the relevant action (Mark Picked Up / Mark Returned) Given device-level notifications are disabled When a prompt time occurs Then an in-app reminder banner is queued and shown on the next app open Given the user’s device timezone differs from the lender’s When prompts are scheduled and displayed Then all times are shown in the user’s device timezone
Blocked Step and Reschedule Suggestions
Given a step cannot proceed When the user selects Mark Blocked and provides a reason Then the system records the reason and timestamp and flags the step as Blocked Given a step is marked Blocked and remaining steps exceed the current schedule When the block is saved Then the app generates at least one reschedule option that fits remaining steps against the live calendar availability Given reschedule options are shown When the user selects an option Then the plan updates and the user is offered to request adjusted pickup/return windows or extend the reservation, including a lender contact option Given no viable timeslots exist When suggestions are generated Then the app informs the user of no availability and offers to notify if a slot opens Given the user declines all suggestions When the block is saved Then the plan remains paused and the next best start time is displayed based on calendar availability
Completion Tracking and Progress Persistence
Given a user completes any checklist item or step while online When the action is saved Then progress is persisted to the server within 5 seconds and the UI reflects the saved state Given the app is closed or the device restarts during an active session When the user reopens Execution Mode Then the last viewed step, checklist states, and step completion statuses are restored exactly as before Given the same user opens the session on a second device When both devices are online Then progress changes sync within 60 seconds and conflicts resolve to the most recent change Given the template is fully completed When the user views the session summary Then it shows count of completed steps, total actual duration, per-step deviation from estimate, and overall variance
Estimate Refinement From Actuals
Given a template step has at least 20 completed actual durations from distinct bookings in the last 90 days When the nightly aggregation job runs Then the step’s estimated duration is updated using a median-based method that excludes the top and bottom 10% of values as outliers Given a step estimate has been updated When a user loads that template Then the step shows the new estimate with an indicator Updated from community data and the percent change from the prior estimate Given an end user has an active execution session When estimate refreshes occur in the background Then the session continues using the estimates captured at session start and does not change mid-run Given estimate updates are applied When an administrator views change history Then the log shows step identifier, previous estimate, new estimate, update timestamp, and sample size used
Organizer Template Authoring & Governance
"As an organizer, I want to create and manage standard project templates for my community so that residents get reliable plans that align with local inventory and rules."
Description

Enable HOA/tenant organizers to author, version, and publish template kits to their neighborhoods. Provide a step and tool editor with validation against inventory, optional approval workflows, and moderation tools for community-submitted templates. Include analytics on template usage, completion rates, savings, and no-show reduction. Support localization and cloning templates across neighborhoods with shared governance policies.

Acceptance Criteria
Authoring: Step & Tool Editor With Inventory Validation
Given an organizer with edit permission in Neighborhood A And Neighborhood A has an inventory catalog of tools When the organizer creates a new template kit and adds steps with required tools and durations Then the editor must auto-suggest tools from Neighborhood A inventory And tools not found in inventory are flagged as "Not in inventory" and block Publish but allow Save as Draft And invalid step durations (non-numeric or <= 0) show inline errors and block Save And required metadata (title, description, category) must be present to save a Draft
Versioning: Draft, Publish, and History with Rollback
Given an organizer saves a template as Draft v0 and publishes as v1.0.0 Then residents see only the latest Published version in the neighborhood library And prior versions remain read-only in Version History with timestamp and publisher When a new version v1.1.0 is published Then the prior version is marked Deprecated and remains valid only for existing reservations And the organizer can Rollback to any prior version, creating a new incremented version with copied content And all version changes are captured in an immutable audit log (user, action, timestamp)
Governance: Optional Approval Workflow Before Publish
Given neighborhood governance has "Require Approval for Templates" enabled and approvers assigned When an organizer submits a template for publish Then the template status becomes Pending Review and it is not visible to residents And approvers receive in-app and email notifications within 5 minutes And approvers can Approve, Request Changes (comment required), or Reject (reason required) And on Approve the template is Published; on Request Changes/Reject the organizer is notified and the template returns to Draft with comments visible And all decisions and comments are recorded in the audit log
Moderation: Community-Submitted Templates
Given community submissions are enabled When a resident submits a template Then the submission appears in the Moderation Queue with status Submitted And automated checks flag prohibited content (e.g., profanity/PII) and safety issues with tags but do not auto-publish And moderators can Edit Metadata, Approve, Request Changes, or Reject (reason required) And the submitter receives notification for each action And approved community templates must still pass governance/approval rules before publish
Analytics: Usage, Completion, Savings, No-Show Reduction
Given at least one published template has bookings within the selected date range When an organizer opens Template Analytics and selects a date range Then for each template the dashboard shows: Total Reservations, Unique Borrowers, Completion Rate (= completed bookings / total bookings), Estimated Savings ($ based on retail tool costs vs. rental), No-Show Rate, and No-Show Reduction vs previous period And metrics update within 15 minutes of booking/reservation events And metric definitions/tooltips are visible And the organizer can export the metrics to CSV for the selected range
Localization: Multilingual Templates and Unit Preferences
Given a neighborhood has a primary language and unit system configured When an organizer provides translations for template title, description, and steps for supported locales Then residents view the template in their preferred language with fallback to the neighborhood primary language And step durations and measurements display in the resident's unit system (metric/imperial) And right-to-left languages render correctly And missing required translations are flagged and block Publish if localization is mandated by governance
Cloning Across Neighborhoods with Shared Governance
Given an organizer has publish rights in Neighborhood A and Neighborhood B When the organizer clones a template from A to B Then a new Draft in B is created with identical content and version label but without active bookings And inventory validation is re-run against B's inventory; missing tools are flagged and block Publish until resolved And source attribution and a link back to the original template are preserved And B's governance policies (including approval workflow) apply to the cloned Draft And the clone action is recorded in the audit log with user, source, target, and timestamp

Deposit Relay

Reduce peak deposit burden with a rolling hold that transfers step-by-step as you progress through the chain. Deposits release at each verified return and extend seamlessly when Drift Guard adjusts timing, keeping lenders protected and borrowers liquid.

Requirements

Rolling Deposit Transfer Orchestration
"As a borrower in a reservation chain, I want my deposit to transfer to the next leg as I return an item so that I never carry multiple large holds at once while keeping lenders protected."
Description

Implement an orchestration layer that atomically releases an existing deposit hold and re-authorizes the next hold in the chain as the borrower advances through bookings. The flow must ensure no moment exists where both holds are simultaneously active beyond necessary overlap, preventing double holds while maintaining continuous lender protection. Integrate with Stripe to perform idempotent operations, handle retries, and guarantee consistency under concurrency (e.g., simultaneous check-in/return events). Include preflight checks for available authorization capacity, chain awareness (previous/next legs), cancellation handling, and safe rollback on errors. Expose telemetry and logs for monitoring transfer success rates and latencies.

Acceptance Criteria
Atomic Transfer Without Double Hold
Given an active deposit hold H1 for leg N and a pending transfer to leg N+1 When the transfer is triggered at handoff (by check-in or scheduled orchestration) Then the system must pre-authorize the next hold H2 successfully before releasing H1 And the measured overlap_ms with both H1 and H2 active is <= configured.maxOverlapMs And upon completion, exactly one hold is active (H2) and H1 is released And if H2 pre-authorization fails, H1 remains active, transfer is aborted, and a user-visible error code is returned And the operation is recorded with a correlation_id and unique idempotency_key
Idempotent Stripe Operations and Retries
Given transient network failures or duplicate delivery of the same transfer event When the orchestration calls Stripe to authorize H2 and release/void H1 using stable idempotency keys derived from chain_id+from_leg_id+to_leg_id+step Then repeated calls with the same idempotency keys within the retry window do not create duplicate holds or duplicate releases And the orchestration retries with exponential backoff up to configured.retryPolicy.maxAttempts while preserving idempotency And the final state after retries is exactly one active hold (H1 or H2) with deduplicated ledger entries And each Stripe request/response is logged with stripe_request_id and idempotency_key
Concurrency: Simultaneous Return and Next Check-In
Given a leg N return event and leg N+1 check-in event arrive within 100ms of each other in any order When the orchestration processes these events under concurrency Then a deterministic outcome is achieved where H2 becomes active and H1 is released And there is no interval with zero active holds during handoff And double-hold duration is <= configured.maxOverlapMs And a distributed lock or compare-and-set on chain_id prevents races, with lock duration <= configured.lockTimeoutMs And no deadlocks or lost updates occur as verified by absence of stalled locks and by successful completion within configured.slo.transferLatencyP95
Preflight Authorization Capacity and Chain Awareness
Given a borrower advancing from leg N to leg N+1 in a multi-leg chain When preflight runs prior to initiating transfer Then the system verifies available card authorization capacity >= next_leg.required_deposit_amount And confirms chain context: leg N state=returned|returning, leg N+1 state=ready_for_check_in And if capacity is insufficient, the system blocks check-in to leg N+1, retains H1, and surfaces an actionable error with remediation options (update payment method, reduce deposit if allowed) And no release of H1 is attempted until capacity for H2 is confirmed
Cancellation and Safe Rollback on Errors
Given a cancellation of leg N+1 before transfer completes or a mid-transfer error occurs When the system processes the cancellation or detects the error Then if H2 is authorized and the next leg is canceled, H2 is immediately voided and H1 is retained (unless the chain ends, in which case H1 is released per policy) And if H1 was released after H2 authorization and H2 subsequently fails irrecoverably, the system attempts to re-authorize H1; on failure, it flags the booking with protection_gap=false, blocks item release, and escalates an incident And borrower and organizer receive notifications within 60 seconds with the current protection state and next steps And all partial states converge to a policy-compliant terminal state with at most one active hold
Telemetry, Metrics, and Logging
Given deposit transfers occur in production When the system emits telemetry Then metrics are available: transfer_success_rate, transfer_latency_ms (p50/p95/p99), overlap_ms (p95), retry_count, rollback_count, idempotent_dedup_count, double_hold_incident_count, failure_rate_by_reason And a dashboard displays success_rate >= configured.slo.successRate (e.g., 99.5%) and p95 transfer_latency_ms <= configured.slo.transferLatencyP95 over the last 24h And alerts fire within 5 minutes when success_rate drops below SLO or double_hold_incident_count > 0 And structured logs include correlation_id, chain_id, leg_ids, stripe_ids, event types, outcomes, durations, and error codes for every transfer step
Drift Guard Timing Adjustments and Hold Extension
Given Drift Guard extends or shifts booking times impacting hold validity When the extension would exceed the current hold's expiration Then the system extends the authorization or performs a seamless re-authorization before expiry so that protection remains continuous And any temporary overlap between old and new authorizations is <= configured.maxOverlapMs And if extension or re-authorization fails, the borrower is prompted to update payment within 2 minutes, continuation is blocked, and the existing hold is retained until alternate protection is established or the booking is terminated per policy
Verified Return Trigger & Evidence
"As a lender, I want deposits to release only after a verified return event so that my item is protected against loss or damage."
Description

Create a verified return mechanism that serves as the authoritative trigger for deposit release and next-leg authorization. Support multiple evidence types (QR/NFC scan, one-time PIN, timestamped geo-photo, lender confirmation, locker sensor event) with fraud checks and tamper-resistant metadata. Define a clear event model: on successful verification, release prior hold and initiate transfer; on disputed or partial return, pause and require review. Provide APIs/webhooks for evidence submission, standardized audit records, and time-boxed SLAs for automated vs. manual approvals. Ensure compatibility with existing pickup/return flows and calendar logic.

Acceptance Criteria
Automated Verification Releases Prior Hold and Relays Deposit
Given a booking with an active deposit hold and a configured next-leg in the Deposit Relay chain When a successful return verification event is recorded for the booking Then the prior deposit hold is released within 3 seconds And the deposit hold is placed on the next-leg booking within 3 seconds of release And a success webhook is emitted to subscribed parties within 2 seconds including verification_id and deposit actions And if no next-leg exists, the chain is closed with status "completed" and no new hold is created
Disputed or Partial Return Pauses Flow for Review
Given a submitted evidence set that fails validation or is flagged as partial/disputed by system or lender When the verification status is set to "disputed" or "partial" Then no deposit release or transfer occurs And the current hold is extended by Drift Guard by at least 24 hours or until resolution per policy And a review case is created with an SLA of 2 business hours for first decision And dispute webhooks are sent with machine-readable reasons and next steps
Multi-Evidence Support with Tamper Checks
Given evidence is submitted as QR/NFC signed token, one-time PIN, timestamped geo-photo, lender confirmation, or locker sensor event When integrity checks run (signature validation, OTP age <= 10 minutes, geo distance <= 50 meters from return location, timestamp within scheduled window ±15 minutes or Drift Guard tolerance, locker event integrity flag = true) Then the system marks verification as "success" if any configured evidence type for the booking passes all required checks And if multi-factor is configured for the org, all required factors must pass for success And reused, expired, or mismatched tokens/OTPs are rejected with specific error codes and audit entries
Evidence Submission API and Webhook Delivery Guarantees
Given an authorized client submits evidence to POST /v1/returns/{booking_id}/evidence with required fields When the payload is valid and authenticated Then the API responds 202 Accepted with verification_id within 500 ms P95 And a verification result webhook is delivered with HMAC-SHA256 signature including verification_id, booking_id, result, deposit_action And webhooks retry up to 7 times with exponential backoff over 24 hours until a 2xx is received And invalid payloads return 400 with machine-readable error codes; unauthorized requests return 401/403
Automated vs Manual Verification SLAs
Given an evidence submission eligible for automated verification When processed by the verification engine Then a success/fail decision is produced within 5 seconds P95 And if routed to manual review, an initial decision is posted within 2 business hours or auto-escalated with notifications And the SLA timers and routing decisions are recorded in the audit record and emitted in webhooks
Standardized Audit Record and Retention
Given any verification attempt (success, fail, partial, or disputed) When the event is processed Then an audit record is persisted within 2 seconds containing: verification_id, booking_id, chain_id, evidence_type(s), result, actor_id, timestamps (received/evaluated/completed), geo (if provided), integrity hash, deposit_action, webhook_status And records are retrievable via GET /v1/audit/verification/{verification_id} to authorized admins And PII is minimized/redacted per policy and records are retained for 24 months; export available in JSON Lines
Calendar and Flow Updates on Verification
Given a booking tied to Sharehood calendar pickup/return windows When verification succeeds Then the item’s availability is updated in the calendar within 3 seconds And the next pickup window is opened or adjusted by Drift Guard according to overlap rules And if verification fails or is disputed, the calendar remains unchanged and the booking shows a hold status to organizers And conflicting bookings are notified if a window shift exceeds 10 minutes
Drift Guard Hold Refresh & Extension
"As a borrower whose booking timing shifts, I want my deposit to extend automatically so that my reservation remains valid without surprise charges or manual steps."
Description

Integrate Deposit Relay with Drift Guard so deposit authorizations extend or refresh seamlessly when pickup/return times shift. Implement proactive renewal before preauthorization expiry per payment network rules, minimizing user friction and avoiding unintended releases. Handle chained reservations by recalculating hold windows and amounts as schedules update, ensuring continuous coverage across overlaps. Provide user-facing notices for upcoming extensions, and implement silent refresh when permitted. Include guardrails for maximum extension duration, incremental re-auth attempts, and fallbacks to alternate payment methods on refresh failure.

Acceptance Criteria
Proactive Hold Refresh Before Network Expiry
Given a borrower has an active preauthorization for amount A with network-provided expiry T_exp And Drift Guard indicates the reservation now ends after T_exp When the current time reaches T_exp minus the configured_refresh_lead_time (default 2 hours) Then the system performs a refresh or re-authorization for amount A on the same payment method And the original hold does not lapse before the new authorization is confirmed (atomic switch) And no duplicate held amount exceeding A is present at any time And the new authorization expiry reflects the network response And the refresh outcome is recorded with request_id and response_code
Schedule Drift Triggers Seamless Hold Extension
Given Drift Guard adjusts pickup or return time later for an active reservation And the new end time exceeds the current hold validity window When the adjustment is applied Then the system recalculates the required hold window and amount to cover the revised schedule And initiates a refresh prior to the current expiry to maintain continuous coverage And performs a silent refresh if permitted by issuer/network And if silent refresh is not permitted, the borrower is prompted to approve within 10 minutes and before current expiry And no gap in authorization coverage occurs at any point
Chained Reservations: Continuous Coverage and Partial Releases
Given the borrower has a chain of reservations covered by Deposit Relay with overlapping/abutting times And an earlier reservation is marked returned and verified at time T_ret When verification is received Then the system releases the portion of the hold attributable to the returned item(s) within 2 minutes of T_ret And maintains a hold equal to the maximum outstanding deposit requirement across remaining reservations And ensures there is zero-second gap in coverage when transitioning between reservations And the per-user held total never exceeds the configured deposit_cap
User Notices and Silent Refresh Rules
Given an upcoming hold extension or re-authorization is scheduled When the extension is ≥ 24 hours away Then send an email and in-app notice 24 hours in advance including amount, new validity window, reason, and cancellation/reschedule options And send a reminder 2 hours before the extension And if the extension is scheduled < 24 hours from reservation creation, send only the 2-hour notice And when a silent refresh is performed, send a post-event receipt within 5 minutes And transactional notices are delivered in the borrower’s locale and bypass muted marketing preferences
Guardrails: Maximum Extension Duration and Retry Policy
Given an authorization has been extended previously When another extension would cause total coverage > Max_Hold_Duration (e.g., 14 days) from initial hold time Then require a fresh full authorization instead of extending again And limit re-auth/refresh retries to Max_Retry_Attempts = 3 within any 24-hour period And apply exponential backoff delays of 1 minute, 5 minutes, and 30 minutes between retries And use incremental authorization when supported; otherwise void the superseded hold after new authorization succeeds
Refresh Failure Fallback to Alternate Payment Method
Given a refresh or re-authorization attempt fails due to decline, expired card, or network error And Max_Retry_Attempts are exhausted or the failure is final When the failure is recorded Then immediately notify the borrower (and organizer where applicable) with a generic reason and next steps And prompt the borrower to add/select an alternate payment method And upon successful authorization on the alternate method, switch coverage atomically with no gap And if alternate method is not provided before pickup, block pickup and cancel per policy And if during an active loan, maintain the current hold until expiry, stop further extensions, and escalate per policy
Audit Logging and Observability for Hold Lifecycle
Given any hold refresh, extension, partial release, success, or failure occurs When the event is processed Then log event_id, user_id, reservation_id, amount_before, amount_after, old_expiry, new_expiry, method (silent/consent), issuer response code, and notification_id And expose the event in the admin audit UI/API within 5 seconds of processing And ensure logs are append-only and tamper-evident And emit metrics for refresh attempts, successes, failures, and trigger an alert if failure rate > 2% over a 15-minute window
Failure Fallbacks & Risk Safeguards
"As an organizer, I want clear fallbacks when a deposit transfer fails so that lenders remain protected and the chain can continue safely or be cleanly canceled."
Description

Define deterministic fallbacks when deposit transfer or refresh fails (insufficient funds, expired card, network error). Policies include: pause the chain handoff, require an alternate payment method, capture the current hold up to policy thresholds, or split/cancel downstream legs while preserving lender protection. Implement configurable timeouts, escalation to organizers, and automated messaging to affected parties. Add risk rules (borrower reputation, item value, history) to adjust required hold amounts or pre-clear alternates. Ensure consistent state recovery with idempotent retries and clear user guidance to resolve blocks.

Acceptance Criteria
Payment Method Failure During Deposit Transfer/Refresh
Given an active Deposit Relay is moving a hold from Leg A to Leg B or refreshing due to Drift Guard When Stripe returns insufficient_funds or expired_card on the hold/refresh attempt Then the chain handoff or refresh is paused within 1 second, the existing hold for the current leg remains authorized, and no duplicate authorization is created And the borrower is immediately prompted to select or add an alternate payment method And an audit log records error code, leg IDs, and timestamp And retries are scheduled per policy (3 attempts at 30s, 60s, 120s) unless an alternate is provided
Network Error with Idempotent Retry and State Recovery
Given a deposit transfer or refresh request times out or fails with a network error When a retry is executed Then the same idempotency key is reused for up to 3 attempts with exponential backoff (e.g., 1x, 2x, 4x) And the system queries the payment processor to reconcile the authoritative hold status before any new action And no duplicate holds or unintended captures exist (exactly one open hold per leg verified via audit) And the booking UI/API consistently reflects a single status (Paused or In-Progress) across reloads
Configurable Timeouts and Organizer Escalation
Given a deposit operation remains unresolved beyond the configured timeout T (default 5 minutes) When T elapses without successful hold/refresh completion Then the relay status is set to Paused and automated messages are sent to borrower and affected lenders within 30 seconds And an escalation notification is delivered to the organizer with controls to override, contact borrower, or adjust policy And automatic retries continue up to R attempts (default 3) unless organizer cancels or borrower supplies a valid alternate
Policy-Limited Partial Capture to Preserve Lender Protection
Given the borrower has custody of the item and policy permits partial capture up to threshold P (e.g., min(25% of deposit, $200)) When payment failures persist beyond window W (default 30 minutes) after alternate method prompts Then the system captures C = min(P, remaining authorized hold) on the current leg And capture reason and policy reference are recorded in audit trail and receipts to the borrower And downstream legs are blocked until remaining required hold is secured or the chain is canceled
Alternate Payment Method Collection and Verification
Given the fallback flow requires an alternate payment method When the borrower adds a new payment source Then AVS/CVV checks and a zero-dollar or $1 refundable authorization are performed And only methods that pass verification and meet risk policy are accepted And upon acceptance, the failed hold/refresh is retried immediately; on success the chain resumes; on failure the flow returns to Paused with resolution guidance displayed
Risk-Based Hold Adjustment and Pre-clearance of Alternates
Given configured risk rules based on borrower reputation score, item value, and borrowing history When a relay step is initiated or retried Then the required hold amount is adjusted per rules (e.g., +20% for low reputation; cap at item value + buffer) And if risk score is below threshold, at least one alternate payment method must be pre-cleared before proceeding And an explainability panel/API exposes rule inputs, matched rule, and resulting hold requirement
Downstream Leg Split/Cancel with Automated Notifications
Given a multi-leg relay where an upstream failure blocks progression beyond timeout or policy limits When split/cancel is triggered by policy Then downstream legs are updated to Paused (split) or Canceled with reason codes And lender protection is preserved by maintaining existing holds/captures per policy And calendar availability updates within 60 seconds, affected parties receive messages with next steps, and a single incident ID links all affected legs in the audit
Multi-Item & Multi-Lender Deposit Consolidation
"As a borrower with several overlapping bookings, I want one consolidated deposit that adjusts per item so that my total hold stays as low as possible while each lender remains covered."
Description

Enable a single consolidated deposit per borrower session that covers multiple items and lenders while allocating liability per item. Compute the required hold as the maximum concurrent exposure across overlapping time windows, and re-balance dynamically as items are picked up/returned. Support partial releases on item-level returns and proportional allocation to lenders for claims. Ensure ledger accuracy when cross-lender bookings are involved, and expose a simple UX summary showing total hold, per-item coverage, and real-time adjustments to minimize peak burden.

Acceptance Criteria
Consolidated Hold Computation for Overlapping Multi-Item, Multi-Lender Bookings
Given a borrower session has multiple items from multiple lenders with defined pickup and return times, When the system computes the required deposit hold, Then the consolidated hold equals the maximum sum of item-level required deposits across all overlapping time windows. Given items in the session have no temporal overlap, When the system computes the hold, Then the consolidated hold equals the highest single-item required deposit across the session. Given an item is canceled before pickup, When recomputing the consolidated hold, Then the canceled item is excluded and the hold does not increase as a result of the cancellation. Given item time windows cross time zones or daylight savings transitions, When computing overlaps, Then calculations use UTC-normalized times and produce identical results regardless of client locale. Given currency rounding rules apply, When computing the consolidated hold, Then the amount is rounded to the smallest currency unit and never exceeds the theoretical maximum exposure by more than one minor unit.
Dynamic Rebalancing on Staggered Pickups and Returns
Given a consolidated hold is active for a session, When an item transitions to Picked Up state, Then internal allocation reflects that lender’s exposure without increasing the total hold unless the new peak exposure exceeds the current hold. Given at least one item remains active, When another item is returned and verified, Then the total hold decreases by at least that item’s remaining required amount within 5 seconds and the remaining allocation is rebalanced across active items. Given Drift Guard adjusts an item’s return time causing a new peak overlap, When recomputing exposure, Then the consolidated hold increases only by the incremental difference required to cover the new peak while maintaining a single active authorization for the session. Given the payment processor rejects a hold decrease request, When the adjustment is attempted, Then the system retries with exponential backoff up to 3 times, preserves current coverage, and logs an actionable error for follow-up.
Partial Release on Item-Level Verified Return
Given an item in the session is marked Returned and passes verification (scan or lender confirmation), When the system processes the return, Then the consolidated hold is reduced by that item’s remaining liability within 5 seconds. Given all items in the session are returned and verified, When recomputing the hold, Then the consolidated hold is fully released within 5 seconds and no additional charges occur. Given a lender disputes the return within the configurable review window, When the dispute flag is set before final release, Then the system pauses the release for the disputed item and notifies the borrower with the reason and next steps. Given an item is returned late, When late fees are calculated, Then the hold reduction first applies to late fees and only the remainder, if any, is released.
Cross-Lender Proportional Claim Allocation
Given multiple lenders have active exposure in a borrower session, When an approved claim (damage, late, or missing) is finalized, Then the captured amount is allocated to lenders proportionally to each item’s approved claim amount, capped by the session’s remaining hold balance. Given total approved claims exceed the remaining hold balance, When capturing funds, Then the system apportions funds pro-rata and records outstanding unpaid amounts per lender. Given a lender retracts an approved claim before capture, When reallocating funds, Then the freed amount becomes available to remaining approved claims within the same session. Given processor fees and currency specifics apply, When posting allocations, Then the ledger records gross claim, fees, net to lender, and borrower adjustments with cent-level accuracy.
Borrower UX: Real-Time Consolidated Hold Summary
Given a borrower has a multi-item session, When viewing the checkout or session summary, Then the UI displays total hold, per-item coverage amounts, each item’s time window, and the projected peak hold. Given pickups or returns change exposure, When such an event occurs, Then the UI updates within 3 seconds to reflect the new total hold and per-item allocations. Given the projected peak will exceed the current hold, When the system determines a hold increase is required, Then the borrower receives a pre-change notice explaining the reason, the new amount, and the effective time, with an option to cancel affected items before the increase is applied. Given the hold decreases due to a verified return, When the adjustment is submitted to the processor, Then the UI confirms the new total and adds a timestamped activity entry showing the delta and the triggering event.
Cross-Lender Ledger Integrity and Reconciliation
Given a session spans multiple lenders, When any deposit hold, release, or capture event occurs, Then balanced double-entry ledger postings are created per lender plus a session-level control entry whose totals match the payment provider to the cent. Given webhook or internal event retries occur, When processing duplicate events, Then the operation is idempotent and no duplicate ledger entries, captures, or releases are produced. Given end-of-day reconciliation is generated, When the report runs, Then each session’s total holds, releases, captures, and fees match payment provider statements with zero tolerance for discrepancies. Given a booking is voided before pickup, When reconciling the session, Then any pre-authorizations are voided and ledger entries reflect a zero net financial effect.
Audit Trail, Receipts, and Real-time Notifications
"As a user, I want transparent status updates and receipts for every deposit action so that I can understand charges and resolve disputes quickly."
Description

Provide a tamper-evident financial ledger that records every deposit event (authorize, extend, transfer, partial release, capture, void) with timestamps, actor, evidence link, and chain context. Generate human-readable receipts and in-app timelines for borrowers and lenders. Send real-time notifications for key events (pre-hold, successful transfer, extension, release, failure), plus daily digests for organizers. Offer exportable reports for disputes and compliance, respecting privacy and retention policies. Surface clear status badges in booking views to reduce support load and increase trust.

Acceptance Criteria
Tamper-Evident Ledger Entries for Deposit Events
Given a deposit event of type authorize, extend, transfer, partial_release, capture, or void is confirmed by the payment processor When the system processes the event Then an append-only ledger entry is created within 1 second containing: ledgerId, bookingId, chainId, predecessorId (nullable), eventType, amount, currency, actorId, actorRole, evidenceLink (URL), status, createdAt (UTC ISO 8601) And the entry cannot be edited via any API; any correction must be a new entry that references the prior ledgerId And the chain integrity checksum is updated and verifiable via the ledger verification endpoint for the chainId And the entry is retrievable by bookingId and chainId with p95 latency under 200 ms for the most recent 90 days And timestamps for entries within the same chainId are strictly monotonic
Human-Readable Receipts and In-App Timelines for Deposit Actions
Given any deposit event is recorded in the ledger When the borrower or lender opens the booking timeline or receipt view Then a human-readable receipt is available within 5 seconds containing: eventType, amount, currency, fees (if any), hold expiration or extension end time, actor label, masked funding source (last4), evidence reference, chain step N of M, and localized timestamp And the receipt has a unique receiptId and a deep link to the evidenceLink And the booking timeline displays all deposit events in chronological order with clear labels matching the event types And the receipt view is printable and exports to PDF with accurate formatting
Real-Time Notifications and Organizer Daily Digest for Deposit Events
Given user notification preferences permit in-app, push, or email When a pre-hold is scheduled, a hold is successfully transferred, an extension is applied, a partial release or full release occurs, or an event fails Then the borrower and lender receive a notification within 15 seconds of event confirmation that includes event type, amount, bookingId, current deposit state, and a deep link to the booking And duplicate notifications for the same eventId are deduplicated per recipient And organizers receive a daily digest at their configured local time summarizing counts and totals of deposit events and any failures requiring attention And all notifications and digests are logged in the audit trail with delivery status
Exportable Audit Reports with Privacy and Retention Enforcement
Given a user with role organizer, admin, or support requests a deposit audit export for a bookingId or date range When the export is generated Then CSV and JSON files are produced within 60 seconds for up to 10,000 records using ISO 8601 timestamps and ISO currency codes with decimal amounts And PII is minimized: emails and phone numbers are masked, funding sources are masked, and evidenceLink is redacted for non-admin roles And the configured retention window is enforced; records older than the window are excluded for non-admin roles And each file includes a SHA-256 checksum and a signed manifest to verify integrity And an audit ledger entry records the export action including requester role, parameters, and file checksums
Deposit Status Badges in Booking Views
Given a booking with an active or historical deposit chain When the borrower or lender opens the booking view on web or mobile Then a status badge displays the current deposit state as one of: Pre-Hold Scheduled, Hold Active, Transferring, Extended, Partial Release, Released, Captured, Void Failed, or Void And the badge updates within 15 seconds after any state change and shows chain step n of m And the badge has accessible labels and tooltips under 140 characters explaining the state And the state and color mapping are consistent across web and mobile clients
Failure Handling, Idempotent Retry, and User Messaging
Given a deposit operation fails due to processor error or network interruption When the system receives the failure or detects a timeout Then a ledger entry is recorded with status=failed, errorCode, errorMessage, correlationId, and retrySchedule And the operation is retried idempotently up to 3 times with exponential backoff using a stable idempotency key to prevent duplicate holds or captures And the borrower, lender, and relevant organizer are notified within 15 seconds with an actionable message including next retry time and a support link And if the final retry fails, the deposit chain state is set to Attention Needed and a support task is created And all retries and outcomes are visible in the booking timeline

Whisper Windows

Auto-schedules ultra-quiet pickup/return slots that honor building quiet hours and elevator traffic, with small buffer cushions to avoid overlap at doorways. Both parties receive haptic-only pre-arrival cues so no doorbells or calls are needed. Reduces disturbance, prevents hallway congestion, and gives off-hours borrowers predictable, stress-free handoffs.

Requirements

Quiet Hours Compliance Engine
"As an HOA organizer, I want Whisper Windows to automatically respect our building’s quiet hours so that handoffs never disturb residents."
Description

The scheduling engine enforces building-defined quiet hours and generates only eligible pickup/return slots for Whisper Windows. It ingests per-property rules (quiet hour ranges, exceptions, stair-only floors, lobby blackout times) and applies them in real time when users browse or modify bookings. The engine validates time zones and daylight saving changes, blocks noisy slot types, and exposes a policy decision API consumed by Sharehood’s live calendar and booking workflows. It supports organizer overrides with audit trails and ensures consistent behavior across web and mobile clients.

Acceptance Criteria
Quiet Hours-Compliant Slot Generation
Given a property defines quiet hours from 22:00 to 06:00 local time, when a user browses pickup/return slots, then only slots fully outside 22:00–06:00 are returned. Given a candidate slot overlaps any portion of quiet hours, when eligibility is evaluated, then the slot is excluded from results and marked ineligible with reason code QUIET_HOURS. Given an item is flagged as NOISY, when candidate slots are adjacent to quiet hours boundaries, then slots violating the property-configured whisper buffer (in minutes) are excluded. Given a booking request time range is provided without a property time zone, when eligibility is evaluated, then the request is rejected with error INVALID_TIMEZONE and no slots are returned.
Exceptions and Blackout Window Handling
Given a property defines a temporary exception lifting quiet hours on 2025-12-31 from 22:00 to 24:00, when a user browses slots for that window, then slots in that window are eligible and not marked as QUIET_HOURS. Given a property defines lobby blackout times from 17:00 to 18:00 daily, when the pickup/return location is Lobby, then slots overlapping 17:00–18:00 are excluded with reason LOBBY_BLACKOUT. Given a property defines stair-only floors from 22:00 to 06:00, when an item requires elevator access to those floors, then slots within 22:00–06:00 are denied with reason STAIR_ONLY_FLOORS. Given overlapping rules (quiet hours and blackout), when eligibility is computed, then the most restrictive outcome is applied and all triggered reasons are returned in the decision.
Time Zone and DST Accuracy
Given property time zone America/New_York and user time zone America/Los_Angeles, when computing eligibility, then all rule evaluations use the property time zone and returned slot timestamps declare the property time zone. Given DST start in America/New_York on 2025-03-09 at 02:00 (nonexistent hour), when generating slots, then no slots are created between 02:00–03:00 local time and boundary rules honor the skipped hour. Given DST end in America/New_York on 2025-11-02 at 01:00 (repeated hour), when generating slots, then slots in the repeated hour are disambiguated by offset and not duplicated; eligibility is consistent across the transition. Given an invalid or unknown IANA time zone in the request, when eligibility is computed, then the engine returns error INVALID_TIMEZONE without generating slots.
Real-Time Evaluation on Browse and Modify
Given a user changes the item or date while viewing available slots, when the change is submitted, then the engine recomputes eligibility immediately and the UI receives an updated slot list reflecting current rules. Given a previously held slot becomes ineligible due to a rule update, when the user attempts to confirm the booking, then the decision is DENY with reason UPDATED_POLICY and at least three alternative eligible slots are returned if available. Given an organizer updates property quiet hours, when users browse or modify bookings, then new decisions reflect the change within 60 seconds across all clients.
Organizer Override with Audit Trail
Given a decision is DENY due to policy rules, when an organizer with override permissions submits an override with a required reason, then the booking is allowed and the decision includes code OVERRIDE_ALLOW and an audit_id. Given an override is submitted without a reason or by a user lacking permissions, when processed, then the override is rejected with error UNAUTHORIZED_OVERRIDE and the deny stands. Given an override is applied to a specific booking, when future eligibility checks occur for other bookings, then the override does not change global rules and applies only to the targeted booking; the audit record captures actor, timestamp, rule_ids, booking_id, and reason.
Policy Decision API Contract and Performance
Given a decision request includes property_id, item_id, action (browse|hold|book|modify|cancel), candidate_time_range, and user context, when processed, then the response returns decision (ALLOW|DENY), reasons[], property_tz, and suggested_alternatives[] when applicable. Given a booking confirmation request includes an idempotency key, when retried within 24 hours, then the API returns the same decision and reference without duplicate side effects. Given nominal load of 50 RPS, when decisions are requested, then p95 latency <= 250 ms and p99 latency <= 600 ms with correctness unchanged. Given an unsupported API version is requested, when processed, then the API returns VERSION_UNSUPPORTED and instructions to upgrade without producing a decision.
Cross-Client Decision Consistency
Given identical inputs from web and mobile clients, when eligibility is requested, then the returned slot set, decision codes, and reasons are identical across clients. Given client-side caches, when a property policy changes, then cached slot data is invalidated and refreshed within 60 seconds on both web and mobile. Given telemetry comparing decisions across clients for the same correlation_id, when analyzed daily, then the decision divergence rate is 0% for identical inputs.
Elevator Load Predictor
"As a borrower, I want my pickup scheduled away from elevator rush times so that the handoff is quick and stress-free."
Description

A predictive module avoids elevator peaks by suppressing Whisper Windows during high-traffic intervals and routing handoffs to less congested times or locations. It supports simple rule-based peak windows configured by organizers and optional learning from historical booking density and building-provided elevator schedules. The predictor feeds constraints to the slot generator and updates availability when real-time conditions change or an outage is reported, with safe fallbacks when data is unavailable.

Acceptance Criteria
Suppress Slots During Organizer-Defined Elevator Peak Windows
Given a building has peak elevator windows configured by the organizer And Whisper Windows slot buffers are set to avoid doorway overlaps When a borrower views or requests a pickup/return during a configured peak window Then no available slot starts, ends, or has buffer overlap within the peak window And the slot generator proposes the nearest available slot outside the peak window And suppressed intervals are labeled with reason code "elevator_peak_rule" When the organizer disables or edits a peak window Then availability reflects the change within 60 seconds for new searches
Organizer Configuration of Peak Windows and Exceptions
Given an organizer defines one or more recurring peak windows with a building time zone When the rules are saved Then overlapping or adjacent windows are merged into a single window And end times that cross midnight are supported via day rollover And invalid ranges (end <= start without rollover) are rejected with inline validation And per-date exceptions can disable specific recurrences (e.g., holidays) And the effective rule set is persisted and retrievable via API including time zone metadata
Learning-Based Congestion Suppression From Historical and Schedule Data
Given learning mode is enabled and at least 30 days of booking density history exist And a building-provided elevator schedule is available (optional) When the predictor generates constraints Then each 15-minute interval receives a congestion score between 0.0 and 1.0 And intervals with score >= the configured threshold (default 0.7) are suppressed And decision metadata includes top contributing signals and sources for auditability And suppression never violates Whisper Windows quiet hours or organizer rules
Real-Time Outage and Surge Recalculation With Notifications
Given a real-time elevator outage is reported or live density exceeds the surge threshold When the event is received by the predictor Then constraints are recomputed and published within 30 seconds And affected future Whisper Windows in the impacted window are marked at risk and suppressed if necessary And borrowers and lenders receive haptic-only alerts with one-tap reschedule options And when the outage clears, suppressed intervals are unsuppressed and stakeholders are notified
Alternate Handoff Location Routing Under Predicted Congestion
Given a selected slot overlaps a predicted congested interval And the building has configured alternate low-traffic handoff locations When the borrower requests alternatives Then the system offers at least one location-based reroute that avoids elevator usage when feasible And each suggestion includes walking ETA and accessibility flags And if no alternate locations exist, only time-based alternatives are proposed
Constraint Feed Integration With Slot Generator
Given the predictor has produced a constraint set for a building and day When the slot generator is invoked Then it receives blocked intervals, preferred handoff locations, and dynamic buffer multipliers And it outputs no Whisper Windows that violate any predictor constraint And each suppressed candidate carries a machine-readable reason code And the response includes constraint_version for traceability
Safe Fallback Behavior When Data Is Unavailable
Given no historical data, no building schedule, and no real-time feed are available When constraints are requested Then only organizer-defined peak windows and Whisper Windows quiet-hour rules are applied And no more than 80% of the service day is suppressed by default And any model or data fetch error triggers a circuit breaker that reverts to rule-only within 5 seconds And an error event is logged with a correlation ID for observability
Buffer Cushion Auto-Insert
"As a lender, I want automatic buffer time around my Whisper Window so that I don’t collide with other neighbors at the door."
Description

The system automatically inserts small pre- and post-slot buffers to prevent doorway overlap and hallway congestion for Whisper Windows. Buffer duration adapts to item class, building layout, and elevator wait estimates, and dynamically expands or contracts when conflicts or late arrivals occur. Buffers are visible in the calendar, protected from regular bookings, and honored in rescheduling logic to maintain quiet handoff flows.

Acceptance Criteria
Baseline Buffer Insertion on Initial Booking
Given a user books a Whisper Window handoff slot with no adjacent bookings at the same doorway, When the booking is confirmed, Then the system inserts both a pre-slot and post-slot buffer that are protected from standard bookings. Given the booking context includes item class, building layout, and current elevator wait estimate, When buffers are computed, Then the total buffer duration equals the value produced by the configured buffer policy for that context. Given buffers are applied, When the calendar is refreshed, Then the buffers appear immediately and the handoff start/end times for the user remain unchanged inside the non-buffer window.
Adaptive Buffer by Item Class and Building Layout
Given two bookings at the same doorway with identical times but different item classes (bulky vs small), When buffers are computed, Then the bulky item booking receives a longer total buffer than the small item booking per policy configuration. Given a building layout marked "narrow hallway/single elevator", When buffers are computed, Then buffer durations are increased according to the layout modifier defined in configuration. Given a buffer policy configuration change is saved, When a new booking is created after the change, Then the computed buffers reflect the new configuration and include a policy version reference in the booking metadata.
Elevator Wait Time Adjustment
Given the building's elevator wait estimate is available, When buffers are computed, Then the pre-slot buffer includes the elevator wait estimate within ±1 minute tolerance. Given elevator wait estimate updates before the handoff, When the new estimate reduces required buffer, Then the system contracts the buffer accordingly without shortening the active handoff window below its minimum duration. Given elevator wait data is unavailable, When buffers are computed, Then the system falls back to the configured default and records the fallback reason in metadata.
Dynamic Buffer Expansion on Late Arrival
Given the borrower’s live ETA intrudes into the current pre-slot buffer, When the ETA update is received, Then the pre-slot buffer expands to maintain no-overlap at the doorway and both parties are notified via haptic-only cues within 15 seconds. Given the expanded buffer would overlap quiet hours or another protected buffer, When expansion is attempted, Then the system proposes the nearest viable adjusted handoff time or marks the booking as requiring manual confirmation without creating overlap. Given buffer expansion occurs, When the calendar is viewed, Then the updated buffers are visible and adjacent bookings remain non-overlapping at the doorway.
Conflict Resolution Without Doorway Overlap
Given two handoffs are scheduled to use the same doorway within a time window that would cause hallway overlap, When both bookings are confirmed, Then the system automatically adjusts buffers and, if necessary, repositions the later booking to eliminate overlap while honoring quiet hours. Given automated adjustments cannot resolve the conflict within policy constraints, When confirmation is attempted, Then the system blocks the action, surfaces a conflict error with involved bookings, and leaves existing confirmed bookings unchanged. Given a conflict is auto-resolved, When audit logs are queried, Then the system records the adjustment rationale, before/after times, and impacted booking IDs.
Calendar Visibility and Booking Protection
Given a booking with buffers exists, When the owner or borrower views the calendar, Then pre- and post-buffers are visibly delineated with duration and reason. Given a non-privileged user attempts to create a booking that overlaps a buffer, When the request is submitted via UI or API, Then the system rejects it with a "buffer-protected" error and no booking is created. Given an admin explicitly overrides a buffer, When the override is confirmed, Then the system allows the booking, records the override in the audit log, and notifies affected parties.
Rescheduling Honors Buffers
Given an existing booking with buffers is rescheduled to a different time, When the new time is saved, Then buffers are recomputed using the current context and applied before/after the new slot while releasing the old buffers. Given the reschedule would force buffer removal below policy minimum, When the user attempts to save, Then the system proposes alternative times that meet buffer policy and prevents saving an invalid arrangement. Given dependent bookings exist adjacent to the rescheduled slot, When buffers are recalculated, Then the system maintains minimum separation from adjacent slots and prevents doorway overlap.
Haptic-only Pre-arrival Cues
"As a borrower, I want silent haptic reminders for my handoff so that I can coordinate without making noise or placing calls."
Description

Mobile clients deliver vibration-only cues to both parties at key moments—slot confirmation, T-15 minutes, arrival window start, and gentle nudges if either party is late—without sounds, calls, or doorbells. Users can opt into device-specific haptic patterns on iOS and Android, with fallback to silent in-app banners if haptics are unavailable. Cues respect system Do Not Disturb and privacy settings and never reveal precise unit numbers, aligning with Whisper Windows’ low-disturbance goals.

Acceptance Criteria
Slot Confirmation Haptic Cue
Given a booking is confirmed and the app is installed on a haptic-capable device and system Do Not Disturb is off When the confirmation event is recorded Then the device emits the configured "confirmation" haptic pattern within 2 seconds and produces no audible sound And the cue is sent exactly once per booking confirmation And the notification content contains no precise unit numbers or apartment identifiers
T-15 Minute Pre-arrival Haptic Cue
Given a participant has an upcoming pickup/return window starting in 15 minutes, haptics are enabled, and Do Not Disturb is off When the timestamp reaches T-15 minutes Then the device emits the configured "pre-arrival" haptic pattern within 30 seconds with no audible sound And no more than one T-15 cue is sent per window per user And if the window is rescheduled, previously scheduled T-15 cues are canceled and only the latest is delivered
Arrival Window Start Haptic Cue
Given the scheduled arrival window begins, haptics are enabled, and Do Not Disturb is off When the window start time is reached Then the device emits the configured "window start" haptic pattern within 10 seconds with no audible sound And the cue is delivered at most once per window per user And it is delivered regardless of whether a T-15 cue was delivered
Late Nudge Haptic Cue Throttling and Stop Conditions
Given either party has not marked arrival within 5 minutes after the window start and haptics are enabled and Do Not Disturb is off When lateness is detected Then the device emits a gentle "late nudge" haptic pattern at T+5 minutes and T+10 minutes with no audible sound And no more than two late nudges are sent per window per user And late nudges stop immediately upon either party marking arrival or when the window ends, whichever occurs first
Device Capability Detection and Silent Banner Fallback
Given a cue is due and the device lacks haptic capability or the user has disabled haptics When the cue is triggered Then no vibration occurs and a silent in-app banner is shown within 3 seconds if the app is foregrounded And if the app is backgrounded, no sound or vibration is produced and the cue is queued for passive display on next app open And the fallback banner contains no precise unit numbers or apartment identifiers
Respect System Do Not Disturb and Privacy Settings
Given system Do Not Disturb is active or the user has restricted vibrations for the app When any cue would otherwise trigger Then the app produces no vibration and no audible sound And if the app is foregrounded, a silent, non-intrusive in-app banner is displayed; if backgrounded, no immediate alert is shown And cue content and metadata never include precise unit numbers or apartment identifiers
User Opt-in and Distinct Haptic Patterns per OS
Given the user opens Notification Settings in the app on iOS or Android When the user opts into haptic-only cues and selects patterns for "confirmation", "pre-arrival", "window start", and "late nudge" Then the selection is saved per device and applied to subsequent cues And default patterns are used when no selection exists And the four cue types are distinguishable by pattern in validation tests with at least 80% correct identification by participants
Whisper-aware Slot Selector UI
"As a user, I want the calendar to clearly show quiet-compliant slots so that I can book confidently without reading building rules."
Description

The booking UI highlights eligible Whisper Windows, hides prohibited times, and explains why a slot is unavailable when quiet hours or elevator constraints apply. It shows buffer cushions, expected haptic cue timeline, and pickup location guidance (e.g., lobby vs. curb) while preserving the simplicity of Sharehood’s live calendar. The UI supports instant re-evaluation when users change item, location, or date and maintains accessibility with contrast-checked badges and screen-reader labels.

Acceptance Criteria
Eligible Whisper Windows Highlighting
Given building quiet hours and elevator peak windows are configured for the selected location, and the user views the booking calendar for an item When the calendar loads or the date changes Then only time slots compliant with quiet hours and elevator constraints are shown as selectable, and Whisper-eligible slots are visually highlighted with a "Whisper" badge And the "Whisper" badge has an accessible name "Whisper Window" and a contrast ratio >= 4.5:1 against its background And non-eligible but still bookable slots remain selectable without the Whisper badge And rendering of the initial month/week/day view completes within 500 ms on a median device
Prohibited Slot Reason Reveal
Given a user taps or focuses a disabled slot on the calendar When the unavailability is due to quiet hours, elevator traffic, or buffer overlap Then an inline tooltip or bottom sheet appears within 150 ms stating a specific reason and timeframe (e.g., "Quiet hours 22:00–07:00", "Elevator peak 17:00–18:30", "Buffer overlap 5 min") And the explanation is exposed to assistive tech via aria-live="polite" and is dismissible via Esc and tap outside And the disabled slot remains non-selectable
Buffer Cushions Display and Conflict Prevention
Given the system calculates pre- and post-slot buffer cushions for doorway/elevator clearance When a user selects or hovers a Whisper window Then the UI shows pre- and post-buffer durations in minutes adjacent to the slot and visually blocks overlapping neighboring slots And attempts to book a slot that would violate buffer cushions are prevented, with the reason "Buffer overlap (X min)" shown And buffer durations update instantly if the slot changes and are consistent across month/week/day views
Haptic Cue Timeline Presentation
Given device capability detection is available When a user selects a slot Then the UI displays a 3-step cue timeline relative to slot start (e.g., -10 min, -2 min, at start) labeled as "Haptic-only" if supported or "Silent visual cue" if not And timeline respects quiet hours (no audible notifications are suggested) And timeline updates immediately if the slot is modified, reflecting new times
Instant Re-evaluation on Item/Location/Date Change
Given the user is on the booking calendar with a selected item and location When the user changes the item, location, or date Then eligible Whisper windows and disabled slots re-evaluate and the UI updates within 250 ms if computed client-side, or within 2.0 s p95 with a loading skeleton if server-side And any previously selected slot that becomes invalid is cleared and an inline alert explains the change And no full page reload occurs
Accessibility and Simplicity Preservation
Rule: All visible badges, disabled states, and guidance text meet WCAG 2.1 AA contrast (>=4.5:1 normal text, >=3:1 large text) Rule: All interactive calendar elements are reachable and operable via keyboard (Tab/Shift+Tab/Enter/Space/Arrow keys), with visible focus indicators Rule: Screen-reader slot labels include date, time, availability, Whisper status, buffer minutes, and pickup location in a single announcement Rule: Minimum interactive target size is 44x44 px; hit targets do not overlap Rule: Booking flow remains single-screen; viewing reason or guidance requires at most 1 additional tap/click; no additional steps added to confirm a slot Rule: Layout shift (CLS) during slot recalculation is < 0.1
Pickup Location Guidance (Lobby vs. Curb)
Given building metadata (interior access allowed, quiet hours, elevator peak windows) and item attributes (size tag), and an organizer location preference When a user selects a slot Then the UI displays "Pickup: Lobby" by default unless any of the following are true: no interior access, item tagged Oversize, or slot intersects elevator peak; in those cases it displays "Pickup: Curb" And the guidance includes a text description and an accessible label; if a map pin is available, it is centered within 300 ms And guidance updates immediately if the user changes item or location
Auto-Reschedule and Quiet Conflict Resolution
"As a borrower, I want the system to suggest a new quiet-friendly slot if a conflict arises so that my plans stay predictable."
Description

When building policies change, an elevator outage occurs, or overlapping buffers emerge, the system proactively proposes quiet-compliant alternatives and, with consent, reschedules Whisper Windows while preserving deposit holds and notifications. Users see the rationale for changes, can accept, pick another slot, or keep the original if allowed by policy, and all adjustments are logged for organizer review.

Acceptance Criteria
Policy Change Reschedule Proposal
Given a building policy update makes an existing Whisper Window non-compliant And the booking start time is more than 60 minutes away When the system processes the policy change Then it proposes at least two alternative time slots on the original date that comply with quiet hours and elevator constraints And each alternative includes a minimum 5-minute pre/post buffer with no doorway overlap And the UI displays a rationale citing the specific policy rule/version And both lender and borrower receive non-auditory notifications within 2 minutes And the existing deposit hold and booking reference remain unchanged
Elevator Outage Alternative Handling
Given an elevator outage is reported overlapping the booked pickup/return window When the system ingests the outage signal Then the original slot is marked as impacted with visible reason And the system proposes alternative quiet-compliant slots outside the outage window And if policy forbids stairwell handoffs during outages, the Keep Original option is disabled with the policy reason shown And both parties are notified within 2 minutes of detection And the deposit hold remains active and is not duplicated
Overlapping Buffer Conflict Resolution
Given two bookings create overlapping buffers at the same doorway/corridor When the conflict engine detects the overlap Then the later-created booking is offered up to three adjusted slot options that eliminate overlap and maintain minimum 5-minute cushions And adjusted options preserve the original date and are within ±45 minutes of the original time unless policy allows broader changes And proposed adjustments do not increase expected hallway concurrency above policy thresholds And the system logs the conflict and proposals with timestamps
Consent and Choice Flow
Given alternative slots have been proposed for a booking When the borrower or lender opens the proposal Then they can Accept a suggested slot, Pick another via a quiet-compliant slot selector, or Keep original if allowed by current policy And selecting Accept immediately reschedules and updates both calendars And selecting Pick shows only slots that satisfy quiet hours, elevator blocks, and buffer rules with visible rationale badges And selecting Keep original requires explicit confirmation and displays the policy reference permitting it And no change is applied without explicit user consent
Audit Log Completeness
Given any reschedule proposal or decision occurs When the event is finalized Then an immutable log entry is stored containing trigger type (policy change/outage/overlap), original slot, proposed slots, selected outcome, user actor, timestamps, policy/version IDs, and notification delivery statuses And organizers can view and export the log within the booking record And log entries are created within 5 seconds of the action
Notification and Payment Integrity
Given a booking is rescheduled with consent When the new slot is confirmed Then the original deposit hold’s payment intent ID is preserved and expiration extended through the new return window And no additional hold or charge is created And lender and borrower receive updated itinerary notifications and haptic-only pre-arrival cues for the new window And if deposit extension fails, the reschedule is rolled back and both parties are notified with an actionable error
Quiet Compliance Validation
Given the scheduler generates alternative slots When validating compliance Then no proposed slot violates building quiet hours, elevator peak blocks, or buffer-overlap rules And each proposed slot is tagged with the exact rules it satisfies And the system rejects any slot that would require audible alerts or phone calls And a compliance check result is displayed before user consent
Building Quiet Policy Profiles
"As an HOA organizer, I want to manage a single quiet policy profile for our building so that all Whisper Window bookings follow the same rules."
Description

Organizers can create and manage reusable profiles that define quiet hours, elevator peak windows, lobby restrictions, allowed pickup locations, and default buffer preferences per property or entrance. Profiles versioning and effective dates ensure future changes do not retroactively alter existing bookings. The scheduling engine and UI consume these profiles to generate and present Whisper Windows consistently across Sharehood.

Acceptance Criteria
Create New Building Quiet Policy Profile
Given an organizer is on the property’s Quiet Policy Profiles screen When they create a profile with quiet hours (including overnight ranges), elevator peak windows, lobby restrictions, allowed pickup locations mapped to entrances, default buffer minutes, and timezone Then the system validates that all time ranges have start != end and are within 24h, allows overnight wrap, and pickup locations exist on the property And the default buffer is an integer between 0 and 60 minutes And the profile saves with a unique ID, version = 1, status = Active, and property/entrance scope And the saved profile is retrievable via API and UI list within 2 seconds with exact entered values
Scheduling Honors Quiet Hours and Elevator Peaks
Given a listing tied to a property/entrance with an Active Quiet Policy Profile When a borrower requests available Whisper Windows for a date range Then the engine does not generate any slots that start, end, or overlap within declared quiet hours And the engine does not generate slots within declared elevator peak windows And each generated slot includes pre/post buffers equal to the profile default and ensures no two slots at the same entrance violate buffer separation And if no compliant slots exist, the API returns an empty set with reason = "policy_constraints"
Profile Versioning with Effective Dates
Given Profile v1 is Active and bookings exist referencing v1 When an organizer publishes v2 with an effective date in the future Then bookings created before publication keep v1 constraints and stored profileVersion = 1 And bookings created on or after the effective date are evaluated against v2 and store profileVersion = 2 And editing a profile creates a new version; past versions remain immutable and viewable in audit history with timestamp, editor, and change summary And when the effective date passes, existing bookings remain unchanged And rescheduling after the effective date evaluates availability against the currently effective profile version
Assign Profile per Property or Entrance
Given a property with multiple entrances When an organizer assigns a profile at the property level and a different profile to a specific entrance Then scheduling for items using that entrance uses the entrance-level profile And scheduling for items without a specified entrance uses the property-level profile And if no profile is assigned, the system applies the global default profile and flags the property as "Unconfigured" in admin UI
UI Presents Whisper Windows From Profile
Given a borrower views the booking UI for a listing bound to a profile When the system displays available times and pickup locations Then only allowed pickup locations from the profile are selectable And times that would violate quiet hours or elevator peak windows are not shown And lobby restrictions are surfaced as inline badges or tooltips on the selected location And adjacent selectable times are spaced to reflect the profile buffer
Rule Conflict Detection and Precedence
Given an organizer attempts to save a profile where a time window conflicts (e.g., elevator peak fully inside quiet hours) When validation runs Then the system accepts overlapping windows but applies precedence at scheduling time as: Quiet Hours (hard block) > Explicit Lobby "no pickup" restrictions (hard block) > Elevator Peaks (block) > Buffers (adjust) And the UI shows a non-blocking warning that overlapping windows exist and documents applied precedence And if all windows combined would result in zero availability for any day, saving is blocked with an error identifying the days impacted
Property Timezone and DST Handling
Given a property timezone is set and a profile includes overnight quiet hours (e.g., 22:00–07:00) When the calendar spans a daylight saving transition Then generated Whisper Windows are computed in the property’s local timezone, maintaining correct wall-clock times And no slot overlaps or gaps are introduced by DST shifts; repeated hours are treated as distinct times by absolute timestamp And all displayed times in UI and API payloads include timezone offsets (e.g., ISO 8601) and a profileVersion field

Ghost PIN

A rotating, proximity‑bound PIN that works even offline and dims for night use. Codes refresh every 30 seconds and only unlock within the geofenced pickup area and time window, then self‑expire after verification. Prevents spoofing and chatter while keeping trust high for cautious lenders and first‑time borrowers.

Requirements

Rotating Offline PIN Engine
"As a borrower, I want to generate and show a valid pickup PIN even without internet so that I can complete handoff reliably in garages, lobbies, or basements."
Description

Implement a cryptographically secure, 6-digit PIN that refreshes every 30 seconds and can be generated and verified fully offline on borrower and lender devices. Each booking receives a unique per-loan secret (seed) provisioned at confirmation and stored encrypted at rest; codes are derived using a truncated HMAC (e.g., HMAC-SHA256) to prevent predictability. The engine tolerates reasonable clock drift with a bounded verification window and rate-limiting to mitigate brute force. Upon successful verification, the active code self-expires to prevent replay. The module must be cross-platform (iOS, Android, and PWA), lightweight, and accessible (large digits, haptics, screen reader labels), with no PII embedded in the code.

Acceptance Criteria
30-Second Rotation via HMAC-SHA256
Given a per-loan seed S and epoch time T, When generating the 6-digit PIN, Then the output matches a reference HMAC-SHA256-based TOTP with step=30s and digits=6 for seed S and time T; And the PIN changes only when floor(T/30) changes and remains constant within each 30s step; And no PII or booking metadata (names, phone, email, address) are inputs to the derivation; And truncation and modulo logic yield values in [000000–999999] with leading zeros preserved.
Deterministic Offline Operation Across Platforms
Given iOS, Android, and PWA devices in airplane mode with identical seed S and epoch T, When each device generates the PIN locally, Then all three produce identical 6-digit codes for T and for T+30s; And no network requests are made during generation or verification; And code generation completes within 15ms p95 on mid-range 2020+ devices (cold <40ms).
Clock Drift Tolerance and Bounded Verification Window
Given borrower time Tb and lender time Tl differ by up to ±90s, And verifier window is configured to ±2 steps (current, ±1, ±2), When the borrower presents a PIN for Tb, Then verification succeeds if Tb maps to any step within the window relative to Tl, And verification fails for codes outside ±2 steps; And the verifier returns the accepted step index and normalization time used.
Brute-Force Mitigation via Rate Limiting
Given a booking context, When more than 5 invalid PIN submissions occur within a rolling 5-minute window, Then further attempts are blocked until a 5-minute cooldown elapses; And the UI shows remaining cooldown time; And attempts and timestamps are recorded locally for later sync; And the counter resets on a successful verification or after cooldown; And limits apply fully offline.
Single-Use Code Self-Expiration (Anti-Replay)
Given a valid PIN for the current step N, When it is successfully verified once, Then any subsequent submission of the same PIN within step N is rejected as a replay with a distinct error; And the next-step PIN (N+1) is eligible to verify if other checks pass; And a successful verification marks step N as consumed for that booking and device pair.
Per-Loan Seed Provisioning and Encryption at Rest
Given a booking is confirmed, When provisioning the engine, Then a unique per-loan seed with ≥128 bits entropy is generated via CSPRNG; And across 100k simulated bookings no seed is duplicated; And the seed is stored encrypted at rest (iOS Keychain WhenUnlocked, Android Keystore AES-GCM with hardware-backed key when available, PWA WebCrypto AES-GCM in IndexedDB); And plaintext seeds never appear in logs, crash reports, or filesystem; And deleting/canceling the booking removes the seed and derived material.
Accessible, Lightweight Display
Given the PIN display screen, When rendered, Then digits are at least 24sp/pt with contrast ratio ≥4.5:1; And VoiceOver/TalkBack announces an accessible label like “Current pickup PIN: 1 2 3 4 5 6” and updates only on rotation; And haptic feedback triggers on each 30s tick (if enabled); And a night mode dims and uses a dark theme automatically with system dark mode or after 20:00 local; And PWA bundle adds ≤50KB gzipped and mobile binary adds ≤150KB; And updates render at ≥50fps on target devices.
Geofenced Unlock Enforcement
"As a lender, I want the code to work only at the designated pickup spot so that my gear cannot be collected elsewhere."
Description

Restrict PIN acceptance to the defined pickup geofence to ensure the code only works at the intended location. The client verifies presence inside a cached, offline-capable geofence (default circular radius with product-configurable meters) using the device’s fused location providers and falls back gracefully with clear UX if permissions are denied or accuracy is low. The verifier cross-checks geofence compliance along with time window before accepting a PIN. Location data is handled with minimal retention and explicit consent prompts to preserve privacy.

Acceptance Criteria
Offline In-Geo, In-Window Acceptance
Given a booking with an active pickup time window and a cached circular geofence (default radius 100 m unless product config overrides) And Location permission is granted And the fused location provider reports the device inside the geofence with reported horizontal accuracy <= 50 m And the device is offline When the borrower enters the current Ghost PIN within its 30-second validity interval Then the verifier accepts the PIN and proceeds with unlock And the decision is returned within 1 second of PIN submission And no network request is attempted during the decision And only a boolean geo_compliant=true and a timestamp are logged without raw coordinates
Out-of-Geofence Rejection and Messaging
Given a valid booking and Location permission is granted And the fused location provider reports the device outside the configured geofence radius by > 10 m When the borrower enters a Ghost PIN Then the verifier rejects the PIN and no unlock occurs And the app displays: "You must be at the pickup location to unlock" And the UI presents actions: "Open Map" and "Try Again" And the attempt is logged with geo_compliant=false and no raw coordinates stored
Out-of-Window Rejection and Messaging
Given a valid booking and the device is inside the geofence with accuracy <= 50 m And the current device time is outside the scheduled pickup window When the borrower enters a Ghost PIN Then the verifier rejects the PIN and no unlock occurs And the app displays: "This code isn’t active right now" And the UI presents actions: "View window" and "Notify lender" And no location coordinates are persisted
Permission Denied Fallback UX
Given Location permission is denied or restricted When the borrower navigates to enter a Ghost PIN Then the app blocks PIN acceptance and explains why location is required to unlock And the UI provides a CTA to "Enable Location" that deep-links to system settings and a secondary "Cancel" action that returns to booking details And no location checks are performed until permission is granted And upon granting permission and returning to the app, geofence enforcement resumes automatically without requiring app restart
Signal Integrity: Low Accuracy and Mock Location
Given Location permission is granted And the fused location provider reports horizontal accuracy > 100 m for at least 10 consecutive seconds OR the device reports mock/simulated location enabled When the borrower enters a Ghost PIN Then the verifier rejects the PIN and no unlock occurs And the app displays: "We can’t verify your location" with guidance to improve accuracy (move outdoors, enable GPS) and a "Retry" action And accuracy is re-evaluated at most once per second upon retry And devices flagged with mock location remain blocked until the flag is cleared
Geofence Configuration and Cache Behavior
Given product configuration defines a circular geofence radius in meters and a cache TTL for offline use (defaults: radius 100 m, TTL 24 h) And the client has previously fetched configuration and geofence for the booking When the device is offline during the pickup window Then the client enforces geofence using the cached radius and center if the cache is valid through the end of the window And if the cache is stale before the pickup window, the app blocks unlock and prompts to refresh with: "Update required to verify location" And when online, config updates to radius are applied within 60 seconds of receipt And the effective radius is clamped to a minimum of 25 m and maximum of 300 m
Privacy and Explicit Consent for Location Use
Given the app will use location to enforce geofenced unlock When the user first attempts to unlock with Ghost PIN Then an explicit in-app consent screen explains purpose, minimal retention, and choices: "Allow" and "Not now" And choosing "Not now" cancels unlock and returns to booking details without requesting system permission And during enforcement, no raw latitude/longitude or device identifiers are stored persistently; only outcome (geo_compliant boolean), timestamp, accuracy (m), and reason code are logged And ephemeral coordinates are discarded within 60 seconds of decision
Time-window Validation and Grace Periods
"As an organizer, I want Ghost PINs to be usable only during the booking window so that handoffs stay orderly and reduce late-night disturbances."
Description

Activate Ghost PINs only within the scheduled pickup/return window with configurable early/late grace periods. The validator consults device time offline and reconciles with server time when available; it displays a live countdown to window open/close, blocks usage outside the window, and clearly explains next steps. On verification, the token self-expires and cannot be reused. Reschedules and extensions automatically re-issue validity without exposing prior codes. Timezone handling, DST changes, and clock drift are fully supported.

Acceptance Criteria
Offline Time Validation Within Pickup Window
Given the device is offline and local device time is within [start - earlyGraceMinutes, end + lateGraceMinutes] When the borrower opens the Ghost PIN screen Then the validator marks the PIN as Active and displays a "Closes in mm:ss" countdown that updates at least once per second Given the device is offline and local time is before start - earlyGraceMinutes When the borrower opens the Ghost PIN screen Then the validator blocks activation and displays "Opens in mm:ss" with the correct remaining time Given the device is offline and local time is after end + lateGraceMinutes When the borrower opens the Ghost PIN screen Then the validator blocks activation and displays "Window closed" with options to Request Extension or Reschedule
Server Reconciliation and Clock Drift Handling
Given the app previously determined state using device time while offline When connectivity is restored and the absolute server time is received Then the app recomputes validity within 2 seconds Given the server/device time delta exceeds configured driftToleranceSeconds When recomputation results in "outside window" Then the PIN is immediately blocked, countdown stops, and a message explains the correction; no codes are revealed Given the time delta is within driftToleranceSeconds or recomputation remains "within window" Then the Active state persists and the countdown re-aligns to server time Given the user manually changes device time When the app is foregrounded Then the validator triggers recomputation using the new device time or server time if available
Grace Period Enforcement (Early and Late)
Given earlyGraceMinutes and lateGraceMinutes are configured for the booking When the borrower attempts to use the PIN at t = start - earlyGraceMinutes Then activation succeeds Given the borrower attempts at t < start - earlyGraceMinutes Then activation is blocked with a "Too early" message and "Opens in mm:ss" Given the borrower attempts at t = end + lateGraceMinutes Then activation succeeds Given the borrower attempts at t > end + lateGraceMinutes Then activation is blocked with "Window closed" and next-step options
Live Countdown and Next-Step Messaging
Given the current state is Not Yet Active When within earlyGraceMinutes Then the UI shows "Opens in mm:ss" updating at least once per second Given the current state is Active Then the UI shows "Closes in mm:ss" updating at least once per second When remaining time <= 60 seconds Then the label switches to "Closing in mm:ss" without revealing or changing the PIN Given the state is Blocked (Too Early or Closed) Then the UI hides the PIN, shows the reason, and presents context-appropriate CTAs: Wait, Request Extension, or Reschedule
Single-Use Token Self-Expiration After Verification
Given the PIN is successfully verified at pickup or return When the verification event is recorded Then the token is marked Consumed locally and on server at next sync and cannot be reused Given any device presents a Consumed token Then validation fails with "Already used" without revealing the prior code Given duplicate verification callbacks occur within 60 seconds Then only one completion is recorded (idempotent) Given verification occurs offline Then a signed consumption record is persisted and synced; the token remains Consumed and does not reactivate
Reschedule/Extension Reissue Without Prior Code Exposure
Given a booking is rescheduled or extended When the change is confirmed Then the previous token sequence is invalidated and a new sequence is issued tied to the new window Given the borrower opens the Ghost PIN screen after the change Then only the new PIN is displayed; any cached prior codes are deleted Given a prior PIN is attempted after reschedule or extension Then validation fails with "Superseded by schedule change" and an audit event is logged Then the countdown recalculates to the new window immediately
Timezone and DST Robustness
Given the booking times are stored in UTC When the borrower device time zone differs from the organizer's time zone Then activation uses UTC boundaries and displays local times correctly with zone abbreviation Given a DST change occurs during the window Then the active period length matches the scheduled duration with no unintended one-hour shift Given the device time zone changes while the app is running Then countdown and labels update within 2 seconds to reflect the new zone
Proximity Handshake Anti-Spoofing
"As a cautious lender, I want the system to confirm the borrower is physically nearby before accepting the PIN so that a leaked code cannot be used remotely."
Description

Augment PIN validation with an offline proximity check (e.g., BLE advertisement/scan or NFC tap) that derives a short-lived verifier from the same booking seed to prove the borrower is physically within a few meters of the lender or pickup box. The handshake prevents remote relay and code-leak exploitation. Provide a manual fallback with additional friction (ID/name confirmation) when radios are unavailable. Implement low-energy scanning, permission gating, background limits compliance, and rate-limiting to avoid chatter and battery drain.

Acceptance Criteria
Offline BLE/NFC proximity handshake within pickup window
Given a confirmed booking with a handshake seed and device clocks within ±60s When the borrower opens the Ghost PIN screen within the geofenced pickup area and scheduled time window with no network connectivity And performs a BLE scan or NFC tap against the lender device/pickup box Then the app derives a short‑lived verifier from the booking seed and current 30‑second time slice that matches the advertiser/reader and completes within ≤1 second And the verifier is accepted only if proximity indicates ≤3 meters (RSSI above threshold or NFC tap present) And only the current or adjacent time slice (±30s) is accepted; older/newer slices are rejected And upon success the verifier and PIN self‑expire and cannot be replayed
Relay and spoofing resistance
Given an attempted handshake from a device located >8 meters away, outside NFC range, or without a matching proximity signal When the borrower enters a valid Ghost PIN or shares it remotely Then the handshake is rejected within ≤1 second and the PIN remains locked And any verifier from outside the geofence or time window is rejected And failures are rate‑limited to ≤5 attempts per minute per booking with exponential backoff (60s after 5 failures; 5 minutes after 10) And all failed attempts are logged with non‑PII metadata (timestamp, reason, booking ID hash)
Geofence and time‑window gating
Given a booking with a defined pickup geofence and start/end time When the borrower is outside the geofence or before the start time or after the end time Then the Ghost PIN and handshake controls are disabled, no scanning is performed, and a clear reason is shown When the borrower enters the geofence within the window Then scanning and handshake are enabled And after verification success or at window end, the PIN and verifier tokens self‑expire and the UI hides the PIN within ≤2 seconds
Energy‑efficient scanning and background compliance
Given the borrower is on the Ghost PIN screen in the foreground When scanning is active Then BLE scans run with a duty cycle ≤20% and auto‑stop after ≤30 seconds of no match And total active scanning per attempt is ≤30 seconds unless the user explicitly retries When the app is backgrounded or the user navigates away Then all scans stop within ≤2 seconds and do not resume until foreground And average battery impact is ≤1% per 5 minutes of continuous scanning on reference devices, verified via instrumentation
Permission and radio gating
Given Bluetooth/NFC is disabled or runtime permissions are not granted When the borrower opens the Ghost PIN screen Then no scanning starts and the user is shown a single in‑context explainer with an action to enable radios/permissions And the OS permission prompt is shown only upon explicit user action And if the user denies twice, scanning remains off and the Manual Fallback path is offered without further prompts And when permissions are granted and radios enabled, scanning can be started only while on the Ghost PIN screen
Manual fallback with added friction and audit trail
Given radios are unavailable, unsupported, or handshake fails after ≥3 attempts When the borrower selects Manual Fallback within the pickup window and geofence Then the borrower must provide full name and present photo ID for lender confirmation and enter the last 4 digits of the phone number on the booking And both borrower and lender must confirm the match on their respective devices before release And upon success, the PIN is consumed, the booking is marked verified via Manual Fallback, and an audit record is stored (timestamp, method, booking ID hash) And the fallback flow enforces a minimum 5‑second confirmation delay before finalizing
Night-safe Display Mode
"As a late-night borrower, I want a dim, high-contrast PIN display so that I can pick up gear discreetly without drawing attention or straining my eyes."
Description

Provide a dedicated PIN screen optimized for low-light use that auto-dims based on ambient light and local sunset while maintaining WCAG-compliant high contrast. The UI uses large, high-contrast digits, minimal glare colors, reduced animations, and brief haptic cues instead of sound. Include a quick toggle to switch brightness modes and an auto-timeout that gently fades the code when the device is moved away from face-view to protect privacy. Ensure parity across iOS, Android, and PWA with accessible theming.

Acceptance Criteria
Auto-Dim Based on Ambient Light and Sunset
Given the PIN screen is visible and ambient light ≤ 10 lux OR local time is between civil twilight (sunset) and sunrise for the device location, When 300 ms elapse, Then Night-safe theme activates and app-level brightness reduction applies within 500 ms. Given ambient light ≥ 30 lux AND time is outside the night interval AND the toggle is not set to On, When 300 ms elapse, Then the standard theme is restored. Then the transition uses opacity-only animation and completes in ≤ 200 ms with no white flash frames. Then on iOS/Android a system brightness request sets brightness to 30–50% of current (if permitted); on PWA an overlay reduces perceived luminance equivalently within ±10%.
WCAG Contrast Compliance in Night Mode
Given Night-safe theme is active, Then all PIN digits and primary text have contrast ratio ≥ 7:1 against background at all supported Dynamic Type/Font Scale sizes. Then essential non-text UI components (toggle, focus ring, buttons, icons) have contrast ratio ≥ 3:1. Given a screen reader is active, When the PIN screen loads, Then all elements expose accessible names/roles, focus order matches visual order, and the visible focus indicator is ≥ 2 px thick and ≥ 3:1 contrast.
Large High-Contrast PIN Digits and Minimal-Glare Palette
Then PIN digits render with a monospaced typeface at ≥ 44 pt (iOS) / 44 sp (Android) on a 375 pt / 360 dp wide viewport and scale up to the largest accessibility size without clipping, truncation, or overlap. Then Night-safe palette uses a dark background (relative luminance ≤ 0.02) and light foreground ensuring contrast ≥ 7:1; no pure-white (#FFFFFF) surfaces are used. Given landscape orientation, Then the digits remain fully visible above the fold with minimum digit height ≥ 32 pt/sp and are centered within ±8 dp/px.
Reduced Motion and Haptic Feedback Instead of Sound
Given system Reduce Motion is enabled OR Night-safe theme is active, Then all nonessential motion is replaced by opacity crossfades ≤ 150 ms; no parallax or large translations occur. Given the PIN refreshes (every 30 s), When haptics are permitted by OS settings, Then exactly one short haptic pulse (10–40 ms) is emitted; no system/app sound is played. Given haptics are disabled or unavailable, Then no haptic or sound is emitted, and visual refresh indication remains accessible (e.g., subtle crossfade).
Quick Brightness Mode Toggle
Given the PIN screen is visible, Then a Night-safe toggle is present and reachable with one tap, offering states: Auto (default), On, Off; its accessible name and state are announced by screen readers. When the user changes the toggle, Then the theme change applies within ≤ 250 ms and the preference persists per device/session until changed. Given toggle=Off, Then ambient/sunset auto-dim never activates; Given toggle=On, Then Night-safe remains active regardless of ambient/time.
Face-View Auto-Timeout with Gentle Fade
Given the PIN screen is visible and there is no user interaction, When face-view is not detected for 10 s (front camera if permission granted; otherwise orientation away > 45° or proximity sensor indicates away), Then the PIN digits obfuscate via opacity fade over 800 ms and are replaced by a non-sensitive placeholder. When face-view is restored within 5 s after obfuscation, Then the digits reappear within ≤ 300 ms without forcing PIN regeneration. Given a screen reader is active and focus is on the PIN screen, Then the auto-timeout is suspended during active navigation to prevent unintended hiding.
Cross-Platform Parity: iOS, Android, and PWA
Given Night-safe theme on iOS, Android, and PWA at comparable viewport sizes, Then layout differences are ≤ 4 dp/px and color token values match design tokens with ΔE ≤ 3 against reference. Given identical triggers (ambient ≤ 10 lux, sunset interval, toggle states), Then activation/deactivation behavior is functionally equivalent across platforms with response time difference ≤ 200 ms. Given offline mode (no network), Then Night-safe behaviors (auto-dim via sensors/time, toggle, auto-timeout) operate without server calls; only local time/location services are used.
Verification Eventing & Deposit/Booking Sync
"As an organizer, I want verified Ghost PINs to automatically update booking status and deposits so that I do not need to reconcile handoffs manually."
Description

On successful PIN (and proximity/geofence/time) verification, publish an idempotent event that transitions the booking state (e.g., Reserved → Picked Up or In Use → Returned), immediately expires the active code, and updates operational systems. Integrate with Stripe to manage deposit holds: confirm hold at pickup and release or adjust at return per policy. Queue events and retry when offline, preserving order, and write an immutable audit log with timestamp, coarse location, device type, and verifier outcomes for trust and support. Notify both parties and update the shared calendar in real time.

Acceptance Criteria
Pickup Verification Success: State Transition, Code Expiry, Notifications, Calendar Update
Given a booking in Reserved state with an active Ghost PIN and the borrower within the geofenced pickup area and scheduled pickup window with proximity satisfied and a valid payment method on file When the borrower enters the correct PIN and the verification succeeds Then the system confirms a deposit hold with Stripe and receives a successful authorization And publishes a single idempotent PickedUp event with idempotency key composed of bookingId and verificationId within 1 second And transitions the booking state from Reserved to Picked Up And immediately expires the active Ghost PIN so it cannot be used again (verification attempts fail thereafter) And updates operational systems (inventory availability and shared calendar) so both parties see the booking as In Use within 3 seconds And sends lender and borrower notifications (push/SMS/email per preference) within 5 seconds And writes an audit log entry capturing timestamp, coarse location, device type, and verifier outcomes
Duplicate Verification Handling (Idempotency and Side‑Effect Safety)
Given a previously successful pickup verification produced a PickedUp event When the same verification is retried or duplicate events with the same idempotency key (bookingId + verificationId + phase) are received within 30 days Then no additional state transitions occur and no duplicate notifications are sent And the API returns a 200 Idempotent response with the original eventId And a single audit log entry is preserved with duplicates annotated as duplicates without creating new side effects
Offline Verification Queuing with Ordered Delivery
Given the borrower completes a successful verification while the device is offline during the pickup window and within the geofenced area When connectivity is restored Then the queued verification event is transmitted within 2 seconds of reconnection using a per-booking monotonic sequence number And the server processes queued events in chronological order with exactly-once effects via idempotency And the booking transitions to Picked Up within 3 seconds after receipt, the PIN remains expired locally and on the server And notifications and calendar updates are delivered within 5 seconds of server receipt And if the event cannot be delivered after 10 retries with exponential backoff (max 10 minutes between retries), the app surfaces a clear recovery prompt while preserving the queue And the server accepts queued events whose signed verification timestamp is within the scheduled window plus a 5-minute grace period
Stripe Deposit Hold at Pickup: Success and Failure Paths
Given a booking with a valid payment method on file When a pickup verification succeeds and the system requests a deposit hold from Stripe Then on authorization success the booking transitions to Picked Up, an authorized deposit amount per policy is held, and the event and notifications are emitted And on authorization failure (e.g., insufficient funds, card declined) the verification is not considered successful, the booking remains Reserved, the Ghost PIN remains active until the end of the pickup window, and both parties are notified with an actionable error And on Stripe timeout or 5xx, the system retries up to 3 times with exponential backoff within 30 seconds total; if still failing, no state transition occurs and a recoverable error is surfaced while the event is queued for retry
Return Verification: State Transition, Deposit Release/Adjustment, Code Expiry
Given a booking in In Use state with an active drop-off window and any return PIN When the borrower completes a successful return verification within the geofence and time window Then the system publishes a single idempotent Returned event within 1 second and transitions the booking state to Returned And immediately expires any active return PIN And updates operational systems and shared calendar to free the time slot within 3 seconds And sends notifications to both parties within 5 seconds And initiates deposit resolution with Stripe: releases the full hold within 1 second of event if no adjustments, or captures/adjusts per policy (e.g., late fees/damages) with itemized amounts, and releases any remainder
Immutable Audit Log Completeness and Integrity
Given any verification (pickup or return) is processed When the event is recorded Then an immutable audit log entry is written with fields: bookingId, eventType (PickedUp/Returned), eventId, idempotencyKey, ISO8601 UTC timestamp to millisecond precision, coarse location (>=100m resolution), device type, verifier outcomes, geofence/time/proximity checks, actorIds, and Stripe outcome where applicable And log storage is append-only (WORM or hash-chained) so entries cannot be modified or deleted; any correction is a new append-only record linked by eventId And support tools can retrieve the entry within 1 second by bookingId or eventId And the system preserves event order per booking and exposes a monotonic sequence number for audit queries

Quiet Nooks

Designate discreet, pre‑approved pickup spots—like a lobby shelf, parcel room cubby, or HOA gear closet—mapped with precise but privacy‑safe directions that appear only during the window. Geofence verification confirms the correct location without messages or calls. Cuts loitering, keeps hallways calm, and standardizes contactless handoffs across buildings.

Requirements

Nook Creation & Approval Workflow
"As an HOA organizer, I want to create and approve designated pickup spots in my building so that residents have a standard, discreet place for contactless handoffs."
Description

Enable building and HOA organizers to create, edit, and approve discrete pickup spots (“Quiet Nooks”) with structured metadata: building association, precise indoor location description, access hours, capacity, allowed item types, photos, and safety notes. Provide an approval queue with version history, change logs, and rollback. Support per-nook rules (quiet hours, max dwell time) and temporary closures. Integrate with Sharehood’s building model so nooks are discoverable only to verified members. Store standardized labels and signage templates to maintain consistency across buildings. Expected outcome: a curated, compliant directory of pre-approved pickup locations ready for scheduling and use.

Acceptance Criteria
Create Nook with Mandatory Metadata
Given an organizer with Manage Nooks permission for Building X When they submit a new Quiet Nook with all required fields: building association (Building X), indoor location description (>=30 characters), access hours (valid weekly schedule, no overlapping ranges, building timezone), capacity (integer > 0), allowed item types (selected from system taxonomy), at least 1 photo (JPEG/PNG, <=5MB each), and optional safety notes Then the system validates inputs, rejects on any invalid field with field-level errors, and on success creates version v1, sets status to Pending Approval, and records an audit log entry with creator, timestamp, and submitted fields
Approval Queue Processing
Given a reviewer with Approve Nooks permission for Building X and a nook in Pending Approval When the reviewer opens the approval queue Then they can see the nook entry with submitted metadata, version v1, submitter, and timestamps And when they Approve with an optional comment Then the nook status changes to Approved, the approval is logged, and the submitter receives a notification And when they Reject with a required reason Then the nook status changes to Rejected, the reason is logged, and the submitter receives a notification
Edit, Versioning, and Rollback
Given an Approved nook When an organizer edits any metadata and submits changes for approval Then a new draft version v(n+1) is created, differences from prior version are recorded in the change log, and the draft enters Pending Approval without altering the live Approved version And when an approver approves the new version Then the live version switches to v(n+1) and the change log displays a diff summary And when a rollback to a previous Approved version is initiated by an approver with a required reason Then the live version reverts to the selected version, a rollback event is logged, and a notification is sent to stakeholders
Configure Per‑Nook Rules (Quiet Hours and Max Dwell)
Given an organizer editing a nook When they set Quiet Hours (one or more day/time ranges) and Max Dwell Time (minutes) Then the system validates that ranges are non-overlapping and within 24h, Max Dwell is between 5 and 180 minutes, and saves the rules with the nook version And when a booking request conflicts with Quiet Hours or exceeds Max Dwell Then the scheduling API rejects the request with a specific error code and message referencing the rule
Temporary Closure Blocks Scheduling
Given an organizer with Manage Nooks permission When they create a Temporary Closure with start/end timestamps (end > start) and a required reason Then the closure is saved, displayed on the nook timeline, and prevents creation of new bookings overlapping the closure via UI and API And when existing bookings overlap the closure Then affected borrowers and the organizer receive notifications with the closure reason and next steps And when the closure expires or is deleted by an organizer Then availability automatically resumes and the audit log records the change
Visibility Restricted to Verified Members
Given Sharehood’s building model and a user’s building membership status When a non-verified or out-of-building user queries for nooks in Building X Then the system does not return the nook, responding with 403/Not Authorized or an empty list without revealing identifiers And when a verified member queries or views a scheduled booking Then the nook is discoverable, and privacy-sensitive details (exact directions) are redacted until within the active pickup window, after which they are displayed
Standardized Labels and Signage Templates
Given an Approved nook with finalized metadata When an organizer requests signage Then the system generates a downloadable PDF using the current template version with standardized labels (building name, nook label, access hours, QR code to booking page, safety notes), meeting WCAG AA contrast and font size minimums And when templates are updated by admins Then new signage uses the latest template version while previously downloaded files remain unchanged, and template versioning is tracked in the repository
Ephemeral, Privacy‑Safe Directions
"As a borrower, I want directions that appear only when I need them so that I can find the pickup spot quickly without exposing residents’ private details."
Description

Provide turn-by-turn, privacy-preserving directions to a designated nook that only become visible to the lender and borrower shortly before and during the active pickup/return window. Mask sensitive details (e.g., apartment numbers), obfuscate precise coordinates, and use relative indoor landmarks and photos. Deliver directions via time-bound deep links that auto-expire and cannot be shared after the window. Localize content and provide accessible text alternatives. Integrate with booking flow to send reminders when directions become available, and conceal them again after the window closes. Expected outcome: clear, time-limited guidance that minimizes hallway loitering and protects resident privacy.

Acceptance Criteria
Time-Bound Visibility of Directions During Pickup/Return Window
Given a confirmed booking with a pickup or return window and default lead time of 15 minutes in the building’s timezone When the current time is earlier than 15 minutes before the window start Then directions are not visible in the UI and the directions API returns HTTP 404 for authorized users Given the current time is within [window start − 15 minutes, window end) When the borrower or lender is authenticated and opens the booking Then the directions are visible in the UI and retrievable via API (HTTP 200) only to those two accounts And any other authenticated or unauthenticated user receives HTTP 403 Given the window has ended When the borrower or lender attempts to view directions Then the UI removes directions within 60 seconds and the API returns HTTP 410 Gone Given a booking is canceled before the window When any user attempts to access directions Then directions remain concealed (UI hidden, API 404)
Deep Link Expiry and Non-Shareability
Given a time-bound deep link is generated for a booking’s active window When opened by the authenticated borrower or lender during the active window Then it resolves to the in-app directions view (HTTP 200) and logs a successful, non-PII access event Given the deep link is opened by any other account, a logged-out user, or from a different tenant When the link is accessed at any time Then an “Expired or Unauthorized” screen is shown and the API returns HTTP 403; no location details, photos, or coordinates are returned Given the window ends When the deep link is accessed Then the API returns HTTP 410 Gone and the page shows an “Expired” state without revealing any sensitive data Rule: The deep link token is bound to booking ID and user role (borrower/lender), contains no address/coordinates/unit info in the URL, and is single-window scoped; token rotation occurs on reschedule and old tokens are invalid immediately
Privacy-Safe Direction Content Masking and Obfuscation
Rule: Directions text must not contain apartment/unit numbers, resident names, phone numbers, or email addresses Rule: Any coordinates delivered are obfuscated to building entrance/centroid and never more precise than 4 decimal places; map pins represent approach point, not the nook Rule: Indoor guidance uses relative landmarks (e.g., “parcel room by elevator A, top shelf”) and excludes unit identifiers Rule: Photos include alt text, have EXIF and geotags stripped, and automatically blur detected faces/license plates before publishing Rule: A content validator blocks saving instructions containing patterns like “apt”, “unit”, “#<digits>” and prompts for privacy-safe revisions Rule: API responses and logs exclude sensitive fields; no raw coordinates, unit numbers, or person names are stored or emitted
Geofence On-Site Verification Without Contact
Given a borrower approaches the designated building When the device location enters the configured geofence (polygon or 25 m radius around the building centroid) Then the app displays on-site verified status and reveals last-step directions (e.g., nook photo and final hint) Given the device is outside the geofence When the borrower attempts to view last-step directions Then the app withholds last-step details and shows only generic approach guidance Given the borrower denies location permission When attempting verification Then the app presents a permission request and a non-contact fallback (e.g., privacy-safe Wi‑Fi SSID presence check); last-step details remain concealed until verification succeeds Rule: On-site verification events store only a boolean and timestamp tied to the booking; no raw latitude/longitude is persisted
Localization and Accessibility of Directions
Given the device locale is supported (e.g., en, es) When directions are displayed Then all text, dates/times, and measurement units are localized; unsupported locales fall back to English Rule: All direction images have meaningful alt text; all interactive elements have accessible names and roles; VoiceOver/TalkBack can read the full instruction flow Rule: Text meets WCAG 2.1 AA color contrast and supports Dynamic Type up to 200% without loss of content Rule: A text-only, step-by-step alternative is provided for any photo-based instruction Rule: Timezones are rendered in the building’s local timezone with clear labels
Booking Flow Reminders for Direction Availability
Given a confirmed booking When the current time reaches 15 minutes before the pickup (and return) window start Then the borrower and lender receive an in-app banner and push notification stating “Directions are now available” without revealing location details, with a deep link to the directions view Given the user was offline at the reminder time When the app next launches before or during the window Then the banner is shown and the push is delivered (if still relevant) without duplicating the message Rule: The booking detail screen shows a countdown to availability and a clear state change to “Available” at the threshold Rule: Notification payloads and previews contain no addresses, coordinates, unit numbers, or photos
Post-Window Concealment and Data Hygiene
Given a booking window ends or the booking is closed/canceled When any party attempts to access directions Then the UI hides all directions immediately and the API returns HTTP 410 Gone; deep link tokens are invalidated Rule: Directions responses are served with Cache-Control: no-store; images use short-lived signed URLs (<10 minutes) so cached media cannot be accessed after expiry Rule: Rescheduling a window invalidates prior tokens at once and issues new tokens scoped to the updated times Rule: Link previews and crawlers receive only generic metadata (no address/coordinates/photos) to prevent unintended disclosure
Geofence & On‑Site Verification
"As a lender, I want automatic verification that the borrower is at the correct pickup spot so that I don’t need to coordinate by messages or calls."
Description

Implement on-device geolocation checks to verify a user is within a configurable geofence radius of the selected nook before enabling pickup/return actions. Set accuracy thresholds and provide fallbacks when GPS is weak (QR/NFC tag at the nook, short PIN code). Require one-tap check‑in/checkout that records time, verification method, and device signals. Trigger automatic status updates, notify the counterpart, and link events to Stripe deposit holds (e.g., release on verified return, flag on no‑show). Log verification events for audits while respecting privacy. Expected outcome: reliable, message‑free confirmation of correct location with minimal friction.

Acceptance Criteria
Enable Pickup Within Geofence
Given a borrower has an active booking and the pickup window is open And the booking has a selected nook with configured geofence radius and accuracy threshold And the device reports a location fix with horizontal accuracy <= the configured accuracy threshold And the computed distance to the nook centerpoint <= the configured geofence radius for at least 5 consecutive seconds And no mock-location/spoof condition is detected When the app evaluates pickup eligibility Then the Pick Up action is enabled And on one tap the booking status changes to Picked Up And a verification event is logged with UTC timestamp, method=GPS, distance_meters, accuracy_meters, device_os, app_version And counterpart and organizer receive an automatic notification And no manual messages or calls are required to complete the pickup Given accuracy > threshold or a spoof condition is detected When the app evaluates pickup eligibility Then the Pick Up action remains disabled And the app prompts the user to verify via QR/NFC or PIN
Enable Return Within Geofence and Release Deposit
Given a borrower’s booking status is Picked Up and the return window is open And the device location accuracy <= configured threshold And the distance to the nook centerpoint <= configured geofence radius for at least 5 consecutive seconds And no mock-location/spoof condition is detected When the user taps Return Then the booking status changes to Returned And the Stripe deposit hold is released within 5 seconds And a verification event is logged with UTC timestamp, method=GPS, distance_meters, accuracy_meters, device_os, app_version And counterpart and organizer receive an automatic notification Given the user is outside the geofence or accuracy > threshold When the user views the Return action Then the Return action is disabled and a reason is displayed with a prompt for QR/NFC or PIN fallback
Fallback Verification via QR/NFC Tag
Given GPS accuracy is > threshold or a spoof condition is detected, or the user opts for fallback And the booking’s pickup/return window is open When the user scans the nook’s registered QR code or taps its registered NFC tag Then the app verifies the tag belongs to the booking’s nook and is active And the relevant action (Pick Up or Return) becomes enabled And on one tap the booking status updates accordingly (Picked Up or Returned) And a verification event is logged with UTC timestamp, method=(QR|NFC), tag_id_hash, device_os, app_version And counterpart and organizer receive an automatic notification And no user messages or calls are required Given the scanned tag does not match the nook or booking, or the window is closed When the scan occurs Then the action remains disabled and an error is displayed
Fallback Verification via Short PIN
Given GPS accuracy is > threshold and QR/NFC are unavailable And the booking’s pickup/return window is open When the user enters the nook’s valid 6-digit PIN Then the relevant action (Pick Up or Return) becomes enabled And on one tap the booking status updates accordingly (Picked Up or Returned) And a verification event is logged with UTC timestamp, method=PIN, device_os, app_version And counterpart and organizer receive an automatic notification Given the user enters an invalid PIN When attempts exceed 5 within 10 minutes Then further PIN attempts are blocked for 5 minutes And the app displays a cooldown message And failed attempts are logged without storing the entered PIN
Admin-Configurable Geofence and Accuracy Thresholds
Given an admin sets a geofence radius per nook between 5 m and 50 m (default 15 m) And sets a location accuracy threshold between 5 m and 50 m (default 20 m) When the settings are saved Then invalid values are rejected with validation errors And valid changes are stored and versioned with UTC timestamp and admin id And mobile clients fetch and apply the new values within 60 seconds And subsequent verifications use the updated values for eligibility decisions And each nook can have distinct settings; unset fields fall back to defaults
Privacy-Safe Audit Logging of Verification Events
Given any pickup/return verification succeeds or fails When the event is recorded Then the log stores event_id, booking_id, nook_id, user_role, user_id, timestamp_utc, verification_method (GPS|QR|NFC|PIN), outcome (success|fail), distance_meters and accuracy_meters if GPS, device_os, app_version And raw latitude/longitude are not stored; only derived distance/accuracy are kept And logs are accessible and exportable (CSV/JSON) to authorized admins only And access to logs is audited with admin_id and timestamp And logs are retained for 180 days and then anonymized; user deletion requests purge associated events
Automated No‑Show and Hold Handling
Given the pickup window expires without a verified pickup event When the window closes Then the booking is marked No-show And the Stripe deposit hold is flagged for review (not released) And borrower, lender, and organizer receive notifications And the event is logged with reason=no_show Given a verified return occurs before the due time When the return is confirmed by any method (GPS|QR|NFC|PIN) Then the Stripe deposit hold is released within 5 seconds And the event is logged with method and timestamp Given the due time passes without a verified return When the due time elapses Then the booking is flagged overdue and the Stripe hold is flagged for review And borrower, lender, and organizer receive notifications
Capacity‑Aware Scheduling & Smart Staggering
"As a resident, I want my pickup time to be automatically staggered based on nook capacity so that I can avoid crowds and complete the handoff quickly."
Description

Allow each nook to define capacity (simultaneous handoffs) and minimum spacing between appointments. The booking engine should auto‑stagger pickup/return windows to reduce hallway traffic, propose alternate times or nearby nooks when conflicts arise, and respect building quiet hours. Dynamically adjust windows when overlaps occur and notify affected users with in‑app confirmations. Surface occupancy forecasts in calendars and avoid bunching during peak times. Integrate with existing Sharehood calendar logic so changes propagate to both lender and borrower. Expected outcome: smoother flows, reduced loitering, and standardized contactless handoffs across buildings.

Acceptance Criteria
Nook Capacity Enforcement During Peak Hour
Given a nook with capacity set to 2 simultaneous handoffs And three bookings are requested that overlap within a 15‑minute window When the third booking is submitted Then the system must prevent overbooking and auto‑stagger the third booking to the nearest available window that keeps concurrent handoffs ≤ 2 And the user is shown at least 3 alternative time slots within the next 60 minutes ordered by lowest occupancy first And no booking is confirmed unless the selected slot satisfies the capacity constraint And at no time shall confirmed overlapping bookings exceed the defined capacity
Minimum Spacing Between Appointments
Given a nook with minimum spacing configured to 5 minutes between appointments And an existing return window ends at time T When a new pickup window is selected that would start earlier than T + 5 minutes Then the system must block the selection and propose the nearest compliant time ≥ T + 5 minutes And spacing rules are enforced on both pickup and return windows for creates and edits And manual overrides that violate spacing are disallowed
Quiet Hours Compliance
Given building quiet hours are configured from 22:00 to 07:00 local time When a booking request overlaps any portion of quiet hours Then those time slots are unavailable for selection And the system suggests at least 2 alternative times outside quiet hours within the next 24 hours And reschedules triggered by capacity or spacing do not move bookings into quiet hours
Nearby Nook Suggestions on Conflict
Given the selected nook is at capacity during the requested window And at least two nearby nooks within 150 meters support the requested item category When the user attempts to book the conflicted time Then the system must present at least 1 alternative time at the original nook and at least 1 alternative nearby nook with compliant windows And each suggestion displays a walking time estimate and occupancy level indicator (low/medium/high) And selecting a nearby nook carries over the item and borrower details without reentry
Occupancy Forecasts and Bunching Avoidance
Given the calendar view for a nook on a selected day When the user opens the calendar Then the system displays hour-level occupancy percentages with a color-coded heatmap (≤40% green, 41–80% amber, >80% red) And the suggestion engine avoids recommending slots with >80% occupancy if any slot within ±60 minutes has ≤80% occupancy And occupancy indicators update within 5 seconds after any booking create, edit, or cancel
Dynamic Adjustment and User Notifications
Given a booking is created or edited in a way that would violate capacity or spacing When the system auto-adjusts one or more booking windows to restore compliance Then all affected borrowers and lenders receive an in-app notification and push alert within 60 seconds And the booking detail view shows the adjusted times with a "changed" badge and records an in-app confirmation when the user taps Confirm And a timestamped audit log entry is stored for each adjustment and confirmation
Calendar Integration and Propagation
Given a booking is confirmed or edited When the event is created or updated Then the change propagates to both lender and borrower Sharehood calendars within 10 seconds And ICS/export feeds reflect the update on the next poll (≤5 minutes) And no duplicate events are created when auto-staggering adjusts times And all times are rendered in the nook's local time zone with correct daylight saving handling
Role‑Based Access & Building Membership Verification
"As a building organizer, I want only verified residents to access Quiet Nooks so that the spaces remain secure and trusted."
Description

Restrict nook visibility and booking to verified building members. Support multiple verification paths (organizer approval, invite code, email domain) and roles (organizer, lender, borrower) with scoped permissions. Ensure only involved parties can see time‑bound directions and verification prompts. Provide revocation on move‑out and emergency suspension of access. Integrate with Sharehood identity and building directories to keep membership current. Expected outcome: secure, least‑privilege access that maintains building trust and prevents misuse.

Acceptance Criteria
Building Membership Verification Paths
Given a user with a verified building email domain, When they sign in, Then their building membership is auto-approved and Quiet Nooks for that building become visible. Given a user with a valid invite code, When they redeem it, Then membership is granted, inviter and timestamp are recorded, and nooks become visible. Given a user submits an organizer approval request, When the organizer approves, Then membership is granted; When rejected, Then access remains denied with a clear reason. Given a non-member user, When they attempt to view building Quiet Nooks, Then the list is hidden and a contextual join prompt is shown. Given an expired or invalid invite code, When redemption is attempted, Then membership is not granted and an error is displayed and logged.
Role-Based Permissions Scope
Given role = Organizer, When managing their building, Then they can invite/approve/revoke/suspend members and configure nook visibility. Given role = Lender, When managing their own items in the building, Then they can create/edit/pause listings but cannot manage members or view other lenders’ PII. Given role = Borrower, When browsing, Then they can view and book eligible items in their building but cannot modify listings or membership. Given any role, When attempting an out-of-scope action, Then the system returns 403 and logs userId, role, action, and timestamp. Given a user in multiple buildings, When acting, Then permissions are scoped per-building and actions cannot affect other buildings.
Time-Bound Directions and Prompts Visibility
Given a confirmed booking, When within the pickup window, Then the borrower and lender can view privacy-safe directions to the Quiet Nook; outside the window, directions are hidden. Given no active booking, When any user requests directions, Then access is denied and no location details are shown. Given an organizer or lender not involved in a specific booking, When browsing, Then only generic nook labels (no directions) are shown. Given a booking ends or is canceled, When the window closes, Then cached directions are purged and the API denies further access to directions. Given a geofence verification prompt, When the borrower is within the geofence during the pickup window, Then the verification UI is shown; When outside the geofence or window, Then it is hidden.
Revocation and Emergency Suspension
Given a member is revoked due to move-out, When revocation is executed, Then building membership tokens are invalidated within 60 seconds and access to nooks/bookings is blocked. Given future bookings owned by a revoked member, When revocation occurs, Then bookings are auto-canceled, parties are notified, and any deposit holds are released within 15 minutes. Given an emergency suspension is applied by an organizer, When enforced, Then access is immediately blocked while preserving data, and organizer can reinstate or convert to revoke with full audit trail. Given a suspended or revoked user, When attempting a protected action, Then the system returns 403 and displays a suspension/revocation message without revealing building details. Given audit requirements, When revocation/suspension occurs, Then an immutable audit entry is created with actor, reason, building scope, and timestamps.
Directory and Identity Sync
Given building directory integration is enabled, When a resident is removed from the directory, Then Sharehood removes building membership within 5 minutes and sends notifications to the user and relevant organizers. Given a new resident is added to the directory, When sync runs, Then a pending membership is created and an invite is sent; no access is granted until verification completes via an approved path. Given a directory API outage, When sync fails, Then retries with exponential backoff occur for up to 24 hours and stale memberships are not re-enabled. Given conflicting statuses between Sharehood and the directory, When detected, Then the directory is treated as source of truth for membership state and a reconciliation report is generated. Given an email change within the same verified domain, When detected, Then membership is preserved and audit logs record the identity change.
Least-Privilege Data Exposure
Given any user not party to a booking, When accessing Quiet Nook data, Then GPS precision is limited to building-level and directions/verification prompts are inaccessible. Given an involved party, When viewing directions, Then no unit numbers, personal names, phone numbers, or PII are displayed; only privacy-safe instructions needed for pickup are shown. Given protected API endpoints, When called with a client token, Then response fields are filtered to the minimum required by the caller’s role and action. Given logging and analytics, When events are recorded, Then no precise location or PII is stored; only hashed identifiers and coarse location per policy are retained. Given security test coverage, When access scopes are enumerated, Then each endpoint enforces least-privilege checks and automated tests cover allow/deny matrices per role and building.
Usage Analytics & Audit Trail
"As an HOA organizer, I want analytics on nook usage so that I can optimize schedules and policies for smoother handoffs."
Description

Capture and aggregate nook usage metrics (bookings, peak hours, average dwell time, failed verifications, no‑shows) and provide an organizer dashboard with filters by building and nook. Maintain an immutable event log for check‑ins/outs and direction visibility events to support dispute resolution and continuous improvement. Respect privacy with aggregation, minimization, and retention policies. Provide CSV export and webhook integrations for building ops tools. Expected outcome: data‑driven oversight to optimize placement, hours, and rules for Quiet Nooks.

Acceptance Criteria
Organizer views aggregated Quiet Nook usage metrics
Given a building-local timezone is configured And bookings with check-ins/outs, geofence verifications, and pickup windows exist within the selected date range When the organizer opens the analytics dashboard and selects a building and date range Then the dashboard displays: total bookings, no-shows, failed verifications, average dwell time (in minutes), and peak hours (top 3 hourly buckets by day-of-week) And peak hours are computed in the building’s local timezone And average dwell time includes only sessions with both check-in and check-out and shows the sample size used And no-shows are counted as bookings with no check-in within the pickup window And failed verifications are counted as geofence verification attempts that did not pass within the pickup window
Organizer filters analytics by building, nook, and date range
Given multiple buildings and nooks exist with data When the organizer applies filters for Building = X, Nook = Y, and Date Range = last 30 days Then all charts, KPIs, and tables reflect only events matching the filters And clearing the Nook filter shows all nooks within Building X And changing the date range updates metrics within 2 seconds for datasets up to 10k bookings
Auditor inspects immutable event log for a booking
Given a booking with directions visibility, check-in, and check-out events When the auditor opens the booking’s event log Then each event shows event_type, timestamp (ISO 8601 with timezone), actor_role, booking_id, nook_id, building_id, and geofence_status where applicable And the log is append-only: attempts to edit or delete an event are rejected with an error And corrections are recorded as new events referencing the prior event_id And an integrity check endpoint returns a valid tamper-evidence proof for the sequence (hash-chain verification passes)
Privacy-preserving analytics, minimization, and retention
Given privacy settings are configured with a raw-event retention period and aggregation rules When viewing dashboards, exports, or logs Then no precise directions content, unit numbers, or exact GPS coordinates are displayed or exported And user identifiers are pseudonymous (non-PII tokens); no email, phone, or name is shown And raw events older than the configured retention period are purged or irreversibly anonymized, while aggregated metrics remain And a retention job report records items processed and is visible to organizers with audit permissions
Organizer exports analytics to CSV
Given active filters for Building = X, optional Nook = Y, and a date range When the organizer clicks Export CSV Then a UTF-8 CSV downloads within 15 seconds containing a header row and one row per day per nook (or per building if Nook is not selected) And columns include: date_local, building_id, building_name, nook_id, nook_name, total_bookings, no_shows, failed_verifications, avg_dwell_minutes, peak_hours_local And values reflect the same numbers shown on the dashboard at the time of export And an empty result still returns a CSV with headers only
Webhook delivery to building ops tools
Given a webhook endpoint with secret S is configured for Building X When any of the following events occur for Building X: directions_visible, geofence_verification_failed, booking_check_in, booking_check_out, booking_no_show Then the system sends an HTTPS POST with a JSON payload including event_type, timestamps, building_id, nook_id, booking_id, and pseudonymous_user_id And each request includes an HMAC-SHA256 signature header derived from secret S and a unique idempotency key And 2xx responses mark delivery complete; otherwise retries occur with exponential backoff for up to 24 hours And redelivery attempts are deduplicated using the idempotency key And payloads exclude PII and precise directions content
Role-based access and data freshness for analytics
Given a user with Organizer role for Building X and a user without access When each user attempts to open analytics for Building X Then the authorized user can view and export analytics; the unauthorized user receives 403 Forbidden And new events appear in the dashboard within 60 seconds of occurrence And 95th percentile dashboard load time is under 2 seconds for up to 10k bookings in the selected date range
Incident Reporting & Escalation
"As a borrower, I want to quickly report a problem at the pickup spot so that the organizer can resolve it and keep the process smooth for everyone."
Description

Offer a lightweight, in‑flow way to report issues at a nook (blocked shelf, missing item, loitering, access problems) with optional photos and auto‑captured context (booking ID, nook ID, timestamp, verification state). Route reports to the right organizer with SLAs, status tracking, and templated updates to affected users. Allow organizers to temporarily disable a nook, post advisories, or reroute upcoming bookings. Integrate with support tooling and maintain an incident history to identify recurring problems. Expected outcome: fast resolution of on‑site issues and consistent building‑wide standards.

Acceptance Criteria
Report Blocked Nook From Pickup Flow
Given I have an active booking within its pickup window and am within the nook geofence, When I tap "Report an issue" on the pickup screen, Then a report form opens pre-filled with booking ID, nook ID, current timestamp (UTC), and geofence verification state, and allows attaching 1–5 photos. Given I submit the form with a selected issue type and optional description/photos, When the submission is sent, Then I receive a success confirmation within 2 seconds and an incident ID is generated. Given the device is offline or has poor connectivity, When I submit a report, Then it is queued and auto-submits within 60 seconds of connectivity restoration without additional user input.
Auto-Captured Context Completeness
Given an incident is created from any surface (pickup flow, booking details, organizer console), When the incident record is stored, Then it contains nook ID, booking ID (if applicable), reporter user ID, timestamp (UTC), and geofence verification state (inside/outside/unknown). Given privacy constraints, When the incident record is persisted, Then precise GPS coordinates are not stored—only the verification state. Given incident updates occur, When any field is changed, Then a versioned audit entry is created with editor ID, field changed, old value, new value, and timestamp (UTC).
Routing To Organizer With SLA and Escalation
Given an incident is created for a nook, When routing executes, Then the incident is assigned to the organizer mapped to that nook/building within 5 seconds. Given the incident type is Safety/Access, When SLA is set, Then the initial response SLA is 15 minutes; Given the incident type is Minor/Maintenance, Then the initial response SLA is 2 hours. Given the SLA timer elapses without status moving to In Progress or Resolved, When escalation rules run, Then the incident auto-escalates to the backup contact and an escalation note is appended and notified. Given the assignee changes the status, When timers apply, Then SLA timers pause/resume appropriately and are logged in the incident timeline.
Templated Notifications To Affected Users
Given a nook incident with status Open and impact = Pickup Blocked, When the incident is created, Then users with active pickup/return windows in the next 6 hours for that nook receive a templated push and email within 2 minutes. Given localized templates exist for the user's language, When the notification is sent, Then the message uses the user's locale; otherwise it falls back to English. Given the template is delivered, When the user opens it, Then it includes the incident summary, current status, ETA (if provided), and a deep link to reroute or reschedule.
Temporarily Disable Nook And Prevent New Bookings
Given an organizer toggles a nook to Disabled in the console, When the change is saved, Then new bookings for that nook are blocked immediately and the nook is hidden from search within 10 seconds. Given the nook is Disabled, When a user with an existing booking views their booking, Then an advisory banner displays with current incident status and options to reroute or reschedule. Given the nook is re-enabled to Active, When the status is saved, Then advisories stop displaying and new booking creation resumes within 10 seconds.
Auto-Reroute Upcoming Bookings
Given a nook is Disabled due to an incident and an alternate nook is configured, When auto-reroute is triggered, Then bookings starting within the next 24 hours move to the alternate nook preserving start/end windows and access instructions. Given no alternate nook has capacity or is configured, When auto-reroute is attempted, Then the booking is flagged for organizer action and the user is notified to reschedule with a deep link. Given an automatic reroute succeeds, When it completes, Then borrower and item owner receive confirmation within 2 minutes and the calendar reflects the new nook location.
Incident History And Support Tool Integration
Given incidents exist for a nook, When viewing Incident History, Then results can be filtered by date range, type, status, and nook and exported to CSV. Given support integration is enabled, When an incident is created, Then a linked ticket is created via webhook within 30 seconds and subsequent status changes sync bi-directionally within 60 seconds. Given ≥3 incidents of the same type occur at the same nook within 30 days, When nightly processing runs, Then a recurring-problem alert is generated and sent to the organizer with a link to the incident cluster.

Haptic Handshake

A vibration‑only confirmation flow that steps users through arrive, verify, place/collect, and exit with tap‑and‑hold gestures—no sounds, screens, or chat required. Both sides get instant, silent receipts and reliability streak credit. Ideal for night‑shift schedules and sleeping households that want proof without noise.

Requirements

Haptic Capability Detection & Silent Fallback
"As a borrower with an older phone, I want the app to tell me if haptics won’t work and offer a quiet alternative so that my pickup doesn’t fail at the door."
Description

Detect device and OS support for system haptics and required background/foreground execution modes before starting a Haptic Handshake. Surface the option only when haptics are available and allowed (respecting system-level haptic settings and Do Not Disturb). Normalize intensity across common devices, run a one-time calibration pulse, and ensure battery- and thermal-safe operation. If unsupported or disabled mid-flow, auto-switch the booking to a quiet, low-visibility confirmation alternative (e.g., dark-screen tap flow or organizer-approved code) while notifying both parties via silent in-app alerts. Log capability flags and fallback reasons for analytics and quality tracking without exposing PII.

Acceptance Criteria
Pre-Handshake Haptic Capability Gate
Given a user views a booking eligible for Haptic Handshake When the device supports system haptics, required foreground/background execution modes are allowed, system haptic feedback is enabled, and Do Not Disturb allows vibrations Then the "Haptic Handshake" option is visible and enabled Given any of those conditions are false When the user views the booking Then the "Haptic Handshake" option is hidden or disabled and the quiet fallback option is presented as default Given capability checks are performed When the booking screen loads Then evaluation completes within 300 ms on median devices
One-Time Haptic Calibration and Intensity Normalization
Given the user selects Haptic Handshake for the first time on a device When the pre-flow begins Then a 2-second calibration sequence plays at three intensities without sound, and the user can accept or adjust to a "Comfortable" level within 15 seconds Given the user saves calibration When subsequent handshakes occur Then vibration intensity is normalized to the saved profile across supported hardware within one vendor intensity step of target Given the device model changes or OS resets haptic settings When a handshake is initiated Then the calibration prompt is shown again one time Given system haptic feedback is Off When calibration would play Then calibration is skipped and the flow falls back silently
Battery and Thermal Safety Guardrails
Given battery saver is active OR battery < 10% and not charging OR device thermal state is Severe/Critical When a Haptic Handshake is about to start Then haptic output does not start, the flow auto-switches to the quiet fallback, and both parties receive silent in-app alerts explaining the switch Given a handshake is in progress When the device enters any of the above unsafe states Then haptic output stops within 500 ms and the flow continues via quiet fallback without user intervention Given guardrail triggers When analytics are logged Then a non-PII fallback reason code "BATTERY_THERMAL" is recorded
Mid-Flow Haptic Disablement Fallback
Given a Haptic Handshake has started When system haptics are toggled Off, Do Not Disturb changes to block vibrations, required execution permission is revoked, or the app loses required foreground/background state Then the flow switches within 1 second to the quiet fallback, preserving step state (arrive/verify/place/exit) and timestamps Given the switch occurs When notifications are sent Then both parties receive silent in-app alerts and no audible tones or system toasts are generated Given fallback occurs When reliability and receipt records are written Then they reflect a successful handshake via fallback with reason code "HAPTIC_DISABLED"
Respect System Haptic Settings and Do Not Disturb
Given system haptic feedback is Off OR Do Not Disturb is set to block vibrations When the user opens a booking Then the Haptic Handshake option is not offered and the quiet fallback is the default Given Do Not Disturb is On but allows vibrations per OS policy When the user opens a booking Then the Haptic Handshake option is offered Given the user changes system haptic or DND settings while on the booking screen When detection re-runs Then the UI updates within 1 second to reflect the correct option availability without navigation
Capability and Fallback Analytics Logging (No PII)
Given capability detection runs or a fallback occurs When an event is logged Then the payload includes only non-PII fields: device class bucket, OS version, app version, haptic_supported flag, execution_mode_ok flag, dnd_state bucket, battery_saver flag, thermal_state bucket, calibration_status, fallback_reason code, timestamps rounded to minute, and a salted booking hash Given logs are persisted When QA queries analytics Then individual names, phone numbers, emails, exact addresses, precise GPS (<1 km), and full booking IDs are not present Given an export is performed When fields are validated Then the schema matches contract and passes an automated PII leakage check
Background/Foreground Execution Mode Validation
Given the app is in foreground When starting a Haptic Handshake Then required execution capabilities are confirmed and haptics can run Given the app is backgrounded with OS-permitted background execution for haptics When continuing a Haptic Handshake Then haptics continue as expected without bringing the app to foreground Given the app is backgrounded without required permission When the handshake would require haptics Then the flow uses the quiet fallback and posts a silent alert prompting the user to reopen the app if needed for non-haptic steps Given execution mode checks run When evaluation fails Then a reason code "EXEC_MODE" is logged
Tap-and-Hold Gesture Recognition Engine
"As a lender juggling items at the doorway, I want simple tap-and-hold gestures that register reliably so that I can confirm handoffs without looking at my phone."
Description

Implement a robust, low-latency recognizer for single hold, double hold, and tap-then-hold gestures with tunable thresholds that work with one-handed use at a doorway. Prevent false positives from pocket presses and motion using accelerometer heuristics. Provide a dark, zero-brightness overlay to avoid visual distraction while capturing input, remaining screenless in practice. Ensure consistent behavior on iOS and Android with device-specific haptic feedback patterns for success, retry, and error states. Provide accessibility options (longer thresholds, lower-intensity patterns) while keeping the flow silent.

Acceptance Criteria
Single Hold Recognition at Doorway (One-Handed)
- Given the dark overlay is active and device motion is low (RMS acceleration ≤ 0.8 m/s² over the prior 500ms), when the user performs a continuous hold within the configured single-hold window (default 700ms; tunable 400–1500ms), then the engine emits SingleHoldRecognized and plays the Success haptic within 50ms. - Given a hold shorter than the lower bound by ≥ 20% or longer than the upper bound by ≥ 20%, when attempted, then no SingleHoldRecognized event is emitted. - Given lab tests across 10 popular devices and three doorway postures, when 100 valid single-hold attempts are made per device, then recognition accuracy is ≥ 98% and median recognition latency ≤ 50ms. - Given the single-hold window is updated via configuration, when applied at runtime, then new values take effect for the next gesture without app restart.
Double Hold Recognition and Misclassification Guard
- Given the overlay is active and device motion is low, when the user performs two holds of 300–800ms separated by a gap of 150–400ms, then the engine emits DoubleHoldRecognized and does not emit SingleHoldRecognized or TapThenHoldRecognized. - Given any component (hold1, gap, hold2) is outside its configured window, when attempted, then no DoubleHoldRecognized event is emitted. - Given 100 valid double-hold attempts per device across 10 devices, then recognition accuracy is ≥ 97% and misclassification as single hold or tap-then-hold is ≤ 1%. - Given tunable ranges for hold1, gap, hold2 (200–1200ms, 100–800ms, 200–1200ms), when updated, then changes take effect immediately for subsequent gestures.
Tap-Then-Hold Sequence Recognition
- Given the overlay is active and device motion is low, when the user performs a tap with contact time ≤ 120ms followed by a hold starting within 300ms and lasting 500–1200ms, then the engine emits TapThenHoldRecognized. - Given the inter-action gap exceeds 300ms or the initial tap exceeds 120ms, when attempted, then the gesture is not recognized as tap-then-hold. - Given 100 valid tap-then-hold attempts per device across 10 devices, then recognition accuracy is ≥ 97% and misclassification as double hold is ≤ 1%. - Given thresholds for tap duration (50–200ms), inter-gap (80–500ms), and hold duration (300–1500ms) are updated at runtime, then the next gesture reflects the new settings without restart.
False Positive Rejection via Motion and Pocket Heuristics
- Given mean linear acceleration > 1.2 m/s² over the 500ms preceding touch, when random contacts occur, then no gesture recognition events are emitted. - Given the proximity sensor reports NEAR for ≥ 200ms during contact (pocket/cover condition), when pressure is applied to the screen, then no gesture recognition events are emitted. - Given a 10-minute walking-with-phone-in-pocket test with randomized screen pressure, then the false positive rate is 0 and recognizer-attributable battery drain is ≤ 1% per hour. - Given the overlay is inactive or the screen is locked, when contacts occur, then no gesture recognition events are emitted.
Zero-Brightness Dark Overlay (Screenless Capture)
- Given capture begins, when the overlay activates, then a full-screen #000000 view with no text/icons is shown and screen brightness is set to 0% (or OS minimum) within 100ms, and prior brightness is restored on exit. - Given an OLED device, when luminance is measured at screen center, then luminance is 0 nits; given an LCD device, then luminance is ≤ 1 nit at minimum brightness. - Given system audio is enabled, when overlay is active and gestures are recognized, then no audio is played and no visual notifications/toasts are shown. - Given VoiceOver or TalkBack is enabled, when the overlay is active, then no spoken announcements are triggered and overlay elements expose no accessibility labels.
Cross-Platform Haptic Feedback: Success, Retry, Error
- Given a gesture outcome (Success, Retry, Error) is emitted, when the event fires, then the device plays the configured outcome-specific haptic pattern within 50ms on both iOS and Android. - Given the three patterns, when measured by duration and/or amplitude, then each is perceptibly distinct: at least one of [pulse count, total duration, peak amplitude] differs by ≥ 30% between any two patterns. - Given a device lacks an advanced haptic API, when an outcome event fires, then a fallback pattern plays and the system logs the fallback without crashing. - Given 100 outcome events per device across 10 iOS and 10 Android devices, then pattern dispatch success rate is 100% and no audio playback is triggered.
Accessibility Presets and Customization (Silent Flow)
- Given Accessibility Mode is ON, when gestures are performed, then all hold thresholds increase by +50% (rounded to nearest 50ms) and the tap threshold increases by +25% by default. - Given Accessibility Mode is ON, when outcome haptics play, then intensity is reduced by 30% (or nearest supported amplitude) and patterns remain perceptibly distinct. - Given a user customizes thresholds within allowed ranges and disables Double Hold, when gestures are attempted, then only enabled gestures are recognized using the custom values, effective immediately. - Given 50 valid attempts per gesture under Accessibility Mode across 6 devices, then recognition accuracy is ≥ 95% and no audio is produced.
Proximity Attestation & Identity Match
"As a lender, I want the handshake to only succeed when I’m next to the right borrower so that I don’t confirm the wrong pickup."
Description

Confirm that the two participants are physically co-located and mapped to the same booking without using screens or audio. Use BLE-based ephemeral tokens with rolling identifiers and RSSI bounds to attest proximity, optionally augmented by NFC tap when available. Bind the handshake to the booking ID server-side and reject attempts from unrelated devices. Design for spotty connectivity by queueing signed proximity proofs locally and finalizing server-side when online. All tokens are short-lived, anonymous, and encrypted to protect user privacy.

Acceptance Criteria
On‑site BLE Proximity Attestation for Pickup/Drop‑off
Given both participants are within the booking’s active time window and have BLE enabled When each user performs the tap‑and‑hold gesture to initiate the haptic handshake Then the devices exchange rolling BLE identifiers within 10 seconds And the measured RSSI on both devices stays ≥ -65 dBm with variance ≤ 6 dB for at least 3 continuous seconds And the received token is unexpired (issued ≤ 60 seconds ago) and not previously used And the server binds the attestation to the booking ID and returns a signed confirmation And both devices emit the success vibration pattern without any audible output
Rejection of Unrelated or Spoofed Devices
Given device A is associated with booking X and device B is not (or presents a token bound to a different booking or expired/stale token) When a haptic handshake is attempted Then the server rejects the attestation and no booking state changes occur And both devices emit the failure vibration pattern without any audible output And the attempt is logged with anonymized metadata and error code And further attempts are rate‑limited to a maximum of 3 failed attempts per 2 minutes per device
Offline Queueing and Deferred Finalization
Given one or both devices lack connectivity when the handshake is performed When a proximity proof is generated locally Then the proof is signed with the device key and stored securely with timestamp, booking ID hash, rolling token IDs, and RSSI summary And the app retries submission with exponential backoff until connectivity returns or 24 hours elapse And upon reconnection within 24 hours, the server verifies the proof, prevents replay via nonce/token tracking, and finalizes the booking step exactly once And both parties receive silent receipts reflecting the original event timestamp And if not submitted within 24 hours, the proof expires and users are prompted to re‑attempt
NFC Augmentation Path (When Available)
Given both devices support NFC and NFC is enabled When users perform a tap during the hold gesture Then an NFC‑derived secret is exchanged and bound to the BLE session on the server And the attestation confidence level is recorded as Strong And if NFC exchange fails within 3 seconds, the flow seamlessly falls back to BLE‑only without sound or screen prompts And analytics record whether NFC was used, failed, or bypassed
Token Privacy, Ephemerality, and Encryption
Given the system issues proximity tokens Then no token contains PII or a raw booking ID; only opaque rolling identifiers are broadcast And tokens rotate every 30–60 seconds with unlinkability across rotations And all over‑the‑air data used for attestation is integrity‑protected and encrypted (e.g., AES‑GCM) with per‑session keys derived from a server challenge And tokens and session keys are retained in memory only and destroyed within 5 minutes And cryptographic parameters are configurable and meet platform security constraints
RSSI Thresholds and Environment Safeguards
Given varied indoor/outdoor conditions and potential physical barriers When a handshake is attempted across distances > 5 meters or through walls/doors Then RSSI thresholds and stability checks prevent success unless apparent distance is within 0.5–2 meters line‑of‑sight And the algorithm requires RSSI within band for ≥ 3 continuous seconds before success And validation testing across ≥ 10 environments demonstrates < 1% false positives and < 3% false negatives at target distance And proximity thresholds are remotely configurable per market and take effect within 15 minutes
Silent Receipts and Reliability Streak Credit
Given server‑side finalization of a successful handshake Then both devices receive distinct short vibration confirmations within 2 seconds, with no audible output or screen alerts And each participant’s reliability streak increments exactly once per completed step (pickup, drop‑off) per booking And receipts and streak updates are delivered even if the counterparty goes offline after local proof generation And the audit log records timestamp, attestation methods (BLE/NFC), and confidence level without storing PII
Silent Step Sequencing & Timeouts
"As a borrower, I want clear, silent haptic cues for each step so that I know when to arrive, verify, collect, and exit without talking or turning on lights."
Description

Guide both parties through arrive, verify, place/collect, and exit using distinct vibration patterns and tap-and-hold confirmations. Each phase has configurable timeouts and retry windows that respect Sharehood’s smart pickup windows and overlap rules. Provide a silent abort pattern if either party cancels. Prevent skipping steps; require successful verify before place/collect, and place/collect before exit. Handle asymmetric progress (one side completes, the other lags) with state reconciliation and idempotent step transitions.

Acceptance Criteria
Distinct Vibration Patterns and Tap‑and‑Hold Confirmation per Step
Given an active booked pickup window and both parties have Haptic Handshake enabled When the flow enters Arrive, Verify, Place/Collect, and Exit Then the device emits four unique, non-overlapping vibration patterns: - Arrive: 2 short bursts (200ms on, 200ms off, 200ms on) - Verify: 1 medium burst (600ms on) - Place/Collect: 3 quick bursts (100ms on, 100ms off, 100ms on, 100ms off, 100ms on) - Exit: 1 long burst (1200ms on) And a tap-and-hold between 1.2s and 2.0s within 10s of the pattern confirms the current step And holds shorter than 1.0s are ignored; holds longer than 2.5s do not confirm And no audible output is produced by the app during the flow
Per‑Step Timeouts Configurable and Enforced Within Smart Pickup Window
Given organizer-configured per-step timeouts between 1 and 15 minutes (1‑minute granularity) When a step is awaiting confirmation Then the step times out at the configured value ±5 seconds And the sum of remaining steps' minimum durations never extends beyond the smart pickup window end; steps are curtailed or blocked accordingly And timeout emits the timeout pattern (two medium bursts: 600ms on, 200ms off, 600ms on) and does not advance the flow
Retry Windows Respect Smart Window and Overlap Rules
Given per-step retry windows configured between 0 and 10 minutes and a defined smart pickup window When a step times out Then the user may re-attempt the same step via tap-and-hold within the retry window and before the smart pickup window end And after the retry window expires or the smart window ends, further confirmations for that step are rejected And overlap rules prevent retries that would collide with the next reservation; the system blocks and emits the overlap-block pattern (4 quick bursts: 100ms on, 100ms off x3, 100ms on)
Silent Abort Pattern and Consistent Cancellation State
Given either party triggers cancel during any step When cancel is received by the system Then both parties' devices emit the abort pattern (long‑short‑long: 800ms on, 200ms off, 400ms on) within 2 seconds And the session state transitions to Canceled atomically; no further step confirmations are accepted And repeating the cancel gesture or receiving duplicate cancel events is idempotent and does not change state again
Step Ordering Enforcement (No Skipping)
Given a session in progress When a user attempts to confirm Place/Collect before Verify has succeeded Then the confirmation is rejected, no state change occurs, and the invalid-order pattern (short‑short‑long: 200ms, 200ms, 600ms with 200ms gaps) plays And Exit cannot be confirmed until Place/Collect has succeeded And only the next available step's pattern is playable; future step patterns cannot be invoked
Asymmetric Progress Handling and State Reconciliation
Given one party has confirmed the current step and the other has not When the lagging party later confirms within the allowed time Then the system reconciles both to the same step and advances exactly once And duplicate confirmations for the same step are handled idempotently (no multiple advancements) And step completion and current state are synchronized to both devices within 1 second of server persistence
Smart Pickup Window and Overlap Compliance for Sequencing and Timeouts
Given a reservation with a smart pickup window that auto-adjusts for overlaps When timeouts or retries would extend the flow past the window end or into an overlapping reservation Then the system reduces remaining retry windows and/or blocks progression so that no step extends past the window end And if the window is shortened due to an overlap, the flow updates both devices' timers within 1 second and applies the new limits immediately
Instant Silent Receipt & Reliability Streak Update
"As a borrower, I want instant, silent proof and streak credit after the handoff so that my reliability improves and I can dispute issues if needed."
Description

On successful exit, generate server-side receipts for both parties, deliver via silent push and in-app inbox, and update reliability streaks in real time. Support offline completion by locally signing the final state and syncing receipts when back online without duplicating credits. Expose a minimal, non-intrusive receipt view from the booking timeline and organizer dashboards. Include structured metadata (booking ID, timestamps, device attestations) for later reference while keeping content noise-free.

Acceptance Criteria
Server Receipt Generation on Successful Exit
Given a booking using Haptic Handshake And both parties complete the Exit step successfully When the server receives the finalized exit event Then the server generates two receipts (one per party) server-side only And each receipt is persisted within 2 seconds (p95) and associated to the booking ID And each receipt has a unique receipt_id and version And no client-generated receipt is accepted And the API responds with a 201 Created including both receipt_ids
Structured Metadata Inclusion and Integrity
Given a server-generated receipt Then the receipt includes: booking_id, receipt_id, lender_id, borrower_id, exit_step_id, server_created_timestamp (UTC ISO8601), start_timestamp, exit_timestamp, device_attestation_lender, device_attestation_borrower, server_signature And timestamps are monotonic: start_timestamp < exit_timestamp <= server_created_timestamp And device attestations are present for both parties or include a reason_code if one is unavailable And server_signature verifies the receipt payload hash And the human-readable content is limited to a single summary line <= 120 chars with no marketing or chat content
Silent Push Delivery with Inbox Fallback
Given receipts are generated When notifications are dispatched Then both parties receive a silent push (no sound, no banner) within 5 seconds p90 and 15 seconds p99 And if a device does not acknowledge within 60 seconds, the receipt appears in the in-app inbox on next app foreground with only a badge/inbox count change And the push payload contains no alert/sound fields and is marked for background delivery And opening the inbox reliably shows the new receipt in < 500 ms p95
Real-Time Reliability Streak Update
Given a booking receipt is created When the server finalizes the exit Then both parties’ reliability streaks update exactly once within 2 seconds (p95) And duplicated finalization events do not change streak counts And streak changes are visible on user profile and organizer dashboards immediately after update And the update is recorded with an audit entry referencing booking_id and receipt_id
Idempotent Credit and Receipt De-duplication
Given the server receives duplicate exit events or retry requests for the same booking When processing with the same idempotency key and booking_id Then only one pair of receipts exists for the booking And any subsequent duplicate requests return 200 with the original receipt_ids And reliability streak increments at most once per booking And notification re-deliveries do not create additional receipts
Offline Exit Signing and Deferred Sync
Given one or both devices are offline at the Exit step When a device locally signs the final state with device attestation and stores it Then upon reconnection within 24 hours the client syncs the signed state And the server verifies signature validity and timestamp freshness (<= 10 minutes skew) before creating receipts And if the counterparty already finalized online, sync does not create duplicate receipts or streak increments And if both parties sync later with valid signatures, the server reconciles to a single receipt pair using the earliest valid exit_timestamp
Minimal, Non-Intrusive Receipt View in Timeline and Dashboards
Given a receipt exists for a booking When a user views the booking timeline or an organizer opens dashboards Then a minimal receipt entry is accessible within one tap And the receipt view displays only: booking_id, counterpart first name, start_timestamp, exit_timestamp, device attestation status, and server_signature status And the view triggers no sounds, haptics, or modals and loads < 500 ms p95 And accessibility labels and focus order allow screen-reader confirmation of metadata And no chat, images, or promotional content is shown
Stripe Deposit Hold & Release Automation
"As an organizer, I want deposits to auto-hold and release based on handshake completion so that I don’t have to manage payments manually."
Description

Integrate step outcomes with Stripe to place a deposit hold at verify, confirm hold at place/collect, and release or convert per policy at exit or no-show. Ensure idempotent webhooks, graceful retries, and reconciliation dashboards for organizers. Surface silent haptic error patterns if payment steps fail and offer retry without exposing payment details at the door. Map failures to policy-driven actions (e.g., reattempt, alternate payment, organizer escalation) while keeping the interaction silent and fast.

Acceptance Criteria
Deposit hold at Verify step
Given a confirmed booking with a deposit requirement and a valid payment method on file, when the borrower completes the Verify haptic step, then the system creates a Stripe deposit authorization for the configured amount within 3 seconds and updates the booking state to "Hold Confirmed". Given the Verify step is retried for the same booking within 10 minutes, when the hold request is sent with the same idempotency key, then exactly one authorization exists in Stripe and the booking shows a single hold. Given Stripe declines the authorization, when the hold attempt fails, then the borrower receives the "hold-failed" haptic pattern within 2 seconds, a silent retry option is presented, and the booking cannot advance to Place/Collect. Given a network timeout occurs during hold creation, when the initial request fails, then the system retries up to 3 times with exponential backoff and records only one successful hold; no payment details are displayed at the door.
Hold verification at Place/Collect step
Given an active deposit hold exists, when the borrower completes the Place/Collect haptic step, then the system verifies the hold is active within 2 seconds and records "Hold Verified at Collect" without re-authorizing. Given no active hold is found at Place/Collect, when policy permits re-authorization, then the system silently re-attempts a hold using the same idempotency key and proceeds only on success; otherwise it emits the "hold-missing" haptic pattern and blocks progression. Given a system-caused error occurs during verification, when Place/Collect is attempted, then both parties receive a silent receipt indicating "Collect deferred" within 10 seconds and the borrower's reliability streak is not penalized.
Release or convert deposit at Exit and No‑Show
Given the Exit haptic step is completed without incidents, when the system processes the deposit, then the authorization is released in Stripe within 5 minutes and both parties receive a silent "release confirmed" receipt and haptic confirmation. Given an incident is recorded per policy (e.g., damage/late return), when Exit is completed, then the system converts the authorization to a charge per policy rules and amount, issues receipts to both parties within 10 seconds, and updates booking and ledger states to "Charged". Given a no‑show is detected after the policy cutoff, when the pickup window ends, then the system converts the authorization per policy or releases it if policy dictates, and notifies the organizer queue for review; all actions remain silent at the door.
Idempotent Stripe webhook handling
Given a Stripe webhook is received, when the signature is verified with the configured secret, then the event is processed exactly once by storing the event ID and ignoring duplicates. Given a webhook cannot be fully processed due to a transient dependency, when handling fails, then the service does not return 2xx, and Stripe retries are accepted and eventually succeed within the retry window with no duplicate holds/charges/releases created. Given an event is malformed or signature validation fails, when the webhook arrives, then it is rejected with 4xx and no state changes occur. Given out‑of‑order events are delivered, when processing them, then the system reconciles final state correctly by querying Stripe as source of truth before committing changes.
Organizer reconciliation dashboard
Given an organizer opens the reconciliation dashboard, when filtering by date range and status, then the list shows each booking's deposit amount, current Stripe state (Authorized/Released/Charged/Failed), timestamps, and policy action taken. Given the organizer exports data, when "Export CSV" is clicked, then a CSV is downloaded containing all filtered rows with totals that match Stripe balance transactions for the same period within $0.01. Given an internal ledger total deviates from Stripe totals by more than $0.01, when the nightly check runs, then a "Mismatch" alert is raised to the organizer within 10 minutes with a link to affected items.
Haptic error patterns and silent at‑door retry
Given a payment failure reason is received (e.g., card_declined, authentication_required, api_connection_error), when translating to user feedback, then a unique haptic error pattern is emitted within 2 seconds and no on‑screen payment details are shown. Given the borrower opts to retry at the door, when a retry is initiated, then up to 2 silent re‑attempts are allowed with backoff, after which the flow escalates to organizer without exposing payment details. Given an error pattern is emitted, when logs are collected, then the specific failure code and attempt count are recorded for audit without storing full PAN or sensitive payment data.
Graceful retries and offline handling
Given temporary network loss occurs at Verify or Place/Collect, when the user completes the haptic step, then the action is queued and a "pending" haptic pattern is emitted every 10 seconds until connectivity returns or a 30‑minute timeout elapses. Given connectivity is restored within 30 minutes, when the queued payment action is sent, then the system completes the hold/verification exactly once using the original idempotency key and proceeds; otherwise the flow escalates to organizer and the booking cannot advance. Given offline conditions persist past timeout, when escalation occurs, then both parties receive silent receipts indicating the reason and next steps, and no duplicate holds are created upon later retries.
Audit Logging & Dispute Evidence Chain
"As support staff, I want a verifiable handshake timeline so that I can resolve disputes quickly and fairly."
Description

Record an immutable timeline of handshake events (step transitions, proximity attestations, timestamped device-side signatures, and Stripe outcomes) to support dispute resolution and chargebacks. Store only necessary, pseudonymized identifiers with a 180-day retention policy. Provide support tools to view the event chain, export evidence bundles, and detect anomalies (e.g., conflicting locations, repeated retries). Ensure logs are tamper-evident and resilient to partial offline operation.

Acceptance Criteria
Tamper‑Evident Hash‑Chained Event Log
Given an audit event is appended for a booking, When it is written, Then the record includes event_hash = SHA-256(canonical_event_payload) and prev_hash matching the prior committed event. Given the verify endpoint is called for a booking, When hashes are recomputed, Then it returns status=Verified for intact chains and status=Compromised with first_bad_event_id for any mutation, deletion, insertion, or reordering. Given a tampering test suite over 100 bookings with 20+ events, When bit-flip, deletion, insertion, and reorder manipulations are applied, Then 100% are detected by the verifier. Given a single-replica read during a multi-replica outage, When verification runs, Then chain integrity remains verifiable using stored hashes without requiring the missing replica.
Complete Handshake Event Coverage and Stripe Outcome Capture
Given a successful Haptic Handshake, When the flow completes, Then the log contains step_transition events for Arrive, Verify, Place/Collect, and Exit in chronological order. Given Verify and Place/Collect steps, When recorded, Then each includes a proximity_attestation with challenge_id, attestation_type ∈ {BLE, NFC}, result ∈ {Passed, Failed}, and an ECDSA P‑256 device_signature over the step payload. Given a booking with a Stripe deposit hold, When hold creation, capture/release, or failure occurs, Then stripe_outcome events are recorded with payment_intent/charge IDs, outcome status, and reason codes within 2 seconds of webhook receipt. Given an aborted handshake, When the flow is canceled, Then a terminal step_transition event with terminal_state=Aborted is recorded.
Data Minimization and 180‑Day Retention
Given audit log persistence, Then only pseudonymized identifiers are stored: booking_id, hashed_user_id (salted), hashed_device_id (salted), role, device_model; no names, phone numbers, chat text, audio, images, or precise GPS traces are stored. Given schema enforcement, When a write attempts to include a disallowed PII field, Then the write is rejected with error AUDIT_PII_BLOCKED and the field is not persisted. Given retention jobs run daily, When a record reaches age 180 days without dispute_hold=true, Then it is purged and becomes unreachable via APIs. Given dispute_hold=true on a booking, When the dispute resolves, Then records are retained until resolution_date + 30 days, after which they are purged on the next cycle. Given a purge run completes, When audit is reviewed, Then deletion audit entries report counts and ID/time ranges for removed records.
Support Timeline Viewer Integrity and Performance
Given a Support user opens a booking timeline, When the page loads, Then events render in chronological order with server_time (UTC), local_time (org timezone), event_type, and an integrity badge ∈ {Verified, Compromised}. Given the Recompute Integrity action, When invoked, Then client-side recomputation matches server verification result for the same chain. Given a booking with 200 events, When loading the viewer, Then initial render completes in ≤2 seconds at p95 and ≤4 seconds at p99. Given a non-privileged user requests the viewer, When access control is applied, Then the request is denied with HTTP 403 and the attempt is audit-logged.
One‑Click Evidence Bundle Export for Chargebacks
Given a Support user clicks Export Evidence for a booking, When the export completes, Then a ZIP is provided containing events.json (canonical order), summary.pdf, stripe_receipts/*.json or *.pdf, manifest.txt with SHA‑256 checksums, and manifest.sig (detached signature). Given the export request, When measured, Then the bundle is available within 15 seconds at p95 and ≤25 seconds at p99 and total size ≤10 MB for bookings with ≤500 events. Given the verify-evidence tool is run on the bundle, When checksums and signatures are validated, Then all files match the manifest and the manifest signature verifies against the platform public key. Given a Stripe dispute workflow, When the bundle JSON is validated, Then required fields (timestamps, amounts, dispute reason mapping) conform to Stripe’s evidence schema without errors.
Offline Event Capture and Idempotent Sync
Given a borrower or lender device is offline during handshake, When steps occur, Then events are queued locally with monotonic sequence numbers, device_timestamps, and device_signatures in secure storage. Given network connectivity is restored, When sync begins, Then queued events upload in order within 5 minutes, preserving original device_timestamps and prev_hash relationships. Given retries cause duplicate submissions, When the server receives an event with an existing event_id or signature, Then it acknowledges idempotently without duplicating the record or breaking the hash chain. Given a mid-sync interruption, When sync resumes, Then no events are lost and the server-side chain matches the device’s queued order as verified by the verifier endpoint.
Anomaly Detection and Alerting on Event Chain
Given two proximity_attestations for the same booking within 60 seconds, When their reported locations differ by >200 meters, Then an anomaly CONFLICTING_LOCATION is recorded and shown in the viewer. Given any step_transition is retried more than 3 times within 10 minutes, When logged, Then an anomaly EXCESSIVE_RETRIES is recorded with counts and timestamps. Given steps occur out of allowed order (e.g., Exit before Verify), When detected, Then an anomaly OUT_OF_ORDER_STEPS is recorded referencing the offending event_ids. Given an anomaly is recorded, When the final relevant event is received, Then an alert is delivered to the Support queue within 60 seconds and the booking is flagged with risk_score ≥ 70.

Night Lockers

Plug‑and‑play support for Bluetooth lockboxes and smart parcel lockers with ephemeral access codes tied to the booking window and Ghost PIN. Sharehood logs a tamper‑resistant access trail and auto‑releases deposits after confirmed return. Enables true zero‑contact swaps so lenders can sleep while borrowers stay on schedule.

Requirements

Ephemeral Access Credential Service
"As a borrower, I want a time-bound code on my phone that unlocks the locker only during my booking window so that I can pick up and return items securely without coordinating in person."
Description

Service to generate and validate time-bound access credentials (BLE keys and keypad PINs) tied to a booking’s pickup/return windows and Ghost PIN. Credentials are single-use or limited-use, scoped to a specific device/compartment, and auto-activate/deactivate with schedule changes and overlap adjustments. Supports early/late buffer rules, revocation, clock drift tolerance, and secure server signing with on-device offline verification for short outages. Issues distinct pickup and return credentials per booking, limits retry attempts, and logs issuance/validation events for auditing. Integrates with Sharehood’s booking engine and mobile apps for seamless delivery to borrowers.

Acceptance Criteria
Time-Bound Activation with Early/Late Buffers
Given an approved booking with pickup window 18:00–19:00 and configured buffers early=10 min, late=15 min When the system issues credentials Then the pickup credential activates at 17:50 and deactivates at 19:15 And any validation attempts outside 17:50–19:15 are rejected with reason=outside_window And all issuance/activation/deactivation events are logged with booking_id, device_id, user_id, timestamps (UTC), and reason codes
Distinct Pickup and Return Credentials Per Booking
Given a booking for device D and compartment C When credentials are issued Then a unique pickup credential and a unique return credential are generated and share no overlapping identifiers And each credential is scoped to device D and compartment C; attempts on other devices/compartments are rejected And the pickup credential is single-use; a second successful validation is rejected with reason=exhausted And the return credential is limited-use with max_uses=3 within the active window; uses persist and enforce while offline
Offline Verification with Signed Tokens and Clock Drift Tolerance
Given the device has no network connectivity for up to 10 minutes And the borrower presents a credential signed by the server using asymmetric keys When the device verifies the signature and checks time bounds with drift_tolerance=±120 seconds Then validation succeeds if within the effective window including tolerance, else fails with reason=time_invalid And no private signing keys reside on the device; only public verification material is present
Revocation and Schedule/Overlap Change Propagation
Given an active credential and the booking is canceled or its time window is adjusted due to overlap resolution When the change is saved Then online devices receive revocation/update within 30 seconds and immediately reject superseded credentials And the borrower app is updated within 10 seconds with the new effective window and refreshed credentials And any validation after revocation_time is logged as denied with reason=revoked And devices that were offline reject the old credential on first sync before allowing access
Retry Limits, Lockouts, and Ghost PIN Masking (Keypad)
Given a 6-digit ephemeral keypad PIN with Ghost PIN enabled When a user enters any 6–12 digit sequence that contains the issued PIN as a contiguous subsequence Then the attempt counts as a single try toward rate limits and is accepted if within window And after 5 failed attempts within 10 minutes, the device enforces a 5-minute lockout for that booking and keypad channel And BLE validations are unaffected by Ghost PIN and follow the same retry/lockout thresholds independently And logs capture attempt outcome, channel=keypad/BLE, masked_length (not raw digits), and failure reason where applicable
Issuance, Delivery, and Audit Logging Integration
Given a booking is created or updated When credentials are issued Then the borrower’s mobile app receives pickup and return credentials via push within 5 seconds (p95) of issuance And credentials are retrievable via the booking API for the borrower with proper auth, never exposed to other users And every issuance and validation event is immutable, queryable by booking_id/device_id for 30 days, and retrievable via admin API within 2 seconds (p95) And each event includes correlation_id to trace end-to-end from issuance to validation outcome
Vendor-Agnostic Device Integration Layer
"As an organizer, I want Sharehood to work with common lockboxes and locker banks so that I can deploy Night Lockers without replacing existing hardware."
Description

Abstraction layer and SDK to integrate Bluetooth lockboxes and multi-compartment smart parcel lockers from multiple vendors. Provides unified APIs for capability discovery (keypad, BLE, cloud unlock), secure key storage, connection management, telemetry (battery, signal, door/bolt state), and compartment addressing. Supports mobile BLE sessions on iOS/Android, cloud API fallbacks where available, keypad-only flows, and firmware/version checks. Enables plug-and-play onboarding of approved hardware models without changing Sharehood’s core booking logic.

Acceptance Criteria
Unified Capability Discovery Across Vendors
Given a certified Bluetooth lockbox with keypad and BLE is powered and in range When discoverCapabilities() is invoked Then the SDK returns a normalized schema including keypad=true, ble=true, cloudUnlock=false, vendor, model, firmwareVersion, and supportedCompartmentAddressing=false within 2000 ms And unsupported capabilities are absent or set to false And the result is identical in structure for at least two different approved vendors of the same capability set Given a smart parcel locker that supports cloud unlock and compartment addressing When discoverCapabilities() is invoked Then the SDK returns keypad=false, ble=false (if not present), cloudUnlock=true, supportedCompartmentAddressing=true and lists the addressing format And errors are reported as structured codes (e.g., DEVICE_UNREACHABLE) without partial capability leakage
Secure Key Material Management
Rule: All device secrets (BLE keys, cloud API tokens) are stored only in OS secure storage (iOS Keychain, Android Keystore) with export-prohibited flags Rule: No SDK API, logs, or serialization outputs ever expose secret material; values are redacted when logging is enabled Given a device is unpaired via sdk.unpair() When the operation completes Then all associated secrets are deleted from secure storage and cannot be retrieved on subsequent calls Given a key rotation is initiated via sdk.rotateDeviceKey() When rotation succeeds Then the device accepts only the new key and the old key no longer authenticates And the SDK updates secure storage atomically with rollback on failure Given a crash or abrupt process kill occurs during key operations When the app restarts Then secrets remain consistent (no partial writes) and operations are idempotent
Mobile BLE Session Control (iOS & Android)
Given an active booking within its valid window and a BLE-capable device in range When sdk.connectBle(deviceId) is called Then a session is established within 3000 ms with encrypted transport and connection status emits CONNECTED Given a session is active for compartment "C-03" When sdk.unlock(compartmentId="C-03") is called Then the device bolt state reports OPEN within 2000 ms And an ACCESS_GRANTED event with timestamp, deviceId, compartmentId, actor=bookingId is emitted to the audit log Given the current time is outside the booking window When sdk.unlock(...) is called Then the SDK rejects with error BOOKING_WINDOW_CLOSED and no BLE command is sent Given radio interference occurs mid-session When the connection drops Then the SDK emits DISCONNECTED, retries up to 3 times, and ensures the device remains secure if unlock confirmation was not received And the session auto-times-out after 30 seconds of inactivity
Cloud API Fallback and Automatic Failover
Given a device supports cloud unlock and local BLE attempts are enabled When sdk.unlock(...) via BLE fails with TIMEOUT within 5000 ms Then the SDK automatically retries once via cloud within 2000 ms using an idempotency key And at most one physical unlock occurs And all attempts are correlated under a single correlationId in the audit trail Given the network is unavailable When cloud fallback is attempted Then the SDK returns SERVICE_UNAVAILABLE and does not report success Rule: Fallback behavior is configurable per device model; when disabled, the SDK must not attempt cloud and must return the original BLE error Rule: All fallback paths produce ACCESS_ATTEMPT events with channel=BLE or channel=CLOUD
Keypad-Only Ephemeral Access Code & Ghost PIN
Given a keypad-only device and a booking from 19:00–20:00 local time When sdk.generateAccessCode(bookingId) is called Then the SDK produces a numeric code tied to the booking and device And the code is valid only between 18:55 and 20:05 (5-minute grace on each side) And the SDK can verify code validity offline Given the correct code is entered on the keypad within the valid window When the device reports code acceptance Then the compartment unlocks and an ACCESS_GRANTED event with method=KEYPAD and bookingId is logged Given the code is entered outside the valid window or after the first successful use (if device enforces one-time use) When the keypad input is processed Then access is denied and ACCESS_DENIED with reason=WINDOW_CLOSED or reason=CODE_REUSED is logged Given the Ghost PIN is entered at any time When processed by the SDK/device Then the device remains locked And a DURESS_DETECTED event is recorded without revealing to the user that access was denied for duress And no access tokens are issued or modified
Telemetry Reporting and Compartment Addressing
Rule: The SDK exposes a normalized telemetry payload: batteryPercent, rssi, doorState, boltState, tamperStatus, firmwareVersion, lastHeartbeatAt Given a multi-compartment locker with 12 compartments When sdk.unlock(compartmentId="C-07") succeeds Then only compartment C-07 transitions to boltState=OPEN and no other compartments change state Given batteryPercent <= 20 When telemetry is received Then the SDK emits a LOW_BATTERY alert event once per 24 hours per device Given tamper is detected by the device When telemetry is received Then TAMPER_DETECTED is logged with signed timestamp and device signature verification passes Rule: Telemetry polling or subscription must deliver updates at least every 60 seconds when a session is active
Firmware/Version Compliance and Model Onboarding
Given a device reports firmwareVersion below the configured minimum for its model When sdk.onboardDevice(...) is called Then onboarding fails with FIRMWARE_OUTDATED and includes minSupportedVersion in the error details Given a device model not on the approved list When sdk.onboardDevice(...) is called Then onboarding fails with UNSUPPORTED_MODEL and no secrets are provisioned Given an approved model at a supported firmware version When sdk.onboardDevice(...) completes Then the device is added to the registry with normalized capabilities And the public SDK interface used by the booking service remains unchanged (contract tests pass without modification) And capability discovery, telemetry, and control commands function without adding model-specific code to the booking service
Tamper-Resistant Access Trail & Audit Logging
"As a lender, I want a trustworthy access history linked to each booking so that I have proof in case of no-shows or damage disputes."
Description

Immutable, append-only audit trail that links every credential issuance, unlock attempt, result, and device telemetry to the booking, user, and device. Events are time-stamped, signed, and stored in WORM-backed storage with hash chaining to deter tampering. Provides UI views and export (CSV/JSON) for organizers, anomaly flags (excess retries, out-of-window attempts), retention policies, and privacy controls (pseudonymized user IDs). Serves as authoritative evidence for disputes and compliance inquiries.

Acceptance Criteria
Event Capture and Linkage to Booking/User/Device
Given an active booking (B), a device (D), a user (U), and an issued access credential (C) When a credential is issued, an unlock attempt occurs, an unlock result is returned, device telemetry is received, or a credential is revoked Then an audit event is recorded within 1 second including: event_type, booking_id=B, device_id=D, user_pid (pseudonymized), credential_pid (pseudonymized), outcome, timestamp, and telemetry_ref And the event has a monotonically increasing sequence number scoped to device D and booking B And the event is available in UI and API queries within 5 seconds of occurrence
Immutable WORM Storage with Hash Chaining
Given an accepted audit event payload When the event is persisted Then it is written to WORM-backed storage and cannot be modified or deleted via application or storage APIs And the event includes previous_hash and hash (SHA-256) forming a continuous chain per device stream And a scheduled integrity verification recomputes the chain daily; any mismatch generates an integrity_alert within 60 seconds and is visible in the admin audit dashboard and via webhook
Signed, Trusted Timestamps
Given an audit event ready to persist When the event is created Then the event timestamp is RFC3339 UTC with millisecond precision and is included in a digital signature (Ed25519) over {payload + previous_hash} And the public key used to verify signatures is published via the platform metadata endpoint And verifying the signature for a stored event returns valid=true; invalid signatures mark the event status=invalid and raise an integrity_alert within 10 seconds
Anomaly Detection and Alerts
Given a booking window [S,E] and device D When more than 3 failed unlock attempts occur within any rolling 10-minute window for booking B or device D Then an anomaly flag 'excess_retries' is attached to booking B and device D and an alert event is emitted and visible in UI within 10 seconds And when any unlock attempt occurs outside [S minus 5 minutes, E plus 5 minutes] Then an anomaly flag 'out_of_window' is created and an alert event is emitted And anomaly flags clear automatically when no violations occur for 24 hours or when booking B is closed
Organizer Audit UI & Export
Given an organizer views the Audit tab for booking B When the event list is loaded Then events are displayed in descending time with filters for event_type, outcome, time range, device, and text search; applying a filter returns results in <= 2 seconds for up to 10,000 events And when Export CSV or JSON is requested for the current filter (up to 100,000 events) Then the export is generated in <= 60 seconds with a SHA-256 checksum, and exported totals match on-screen counts exactly
Privacy and Pseudonymization Controls
Given a user U without PII_View role When viewing audit events Then user identifiers are shown as pseudonymous user_pid stable per organization, with no email, phone, or full name displayed And raw access codes are never stored; only salted hashes are persisted and displayed as redacted And all attempts to reveal PII are blocked and are themselves logged as audit events Given an admin with PII_View role When toggling 'Reveal PII' for a session Then PII fields are revealed for 15 minutes and every reveal action is logged with actor and purpose
Retention and Legal Hold
Given a default retention period of 24 months When an event reaches its retention end Then it is queued for purge and a tombstone record with event hash, type, and purge_time is appended to the audit log; purge completes within 7 days And given a legal hold on booking B or device D When retention end is reached Then affected events are retained until the hold is removed; holds are listed with reason, actor, and timestamp And all purge and hold actions are themselves recorded as immutable audit events
Zero-Contact Pickup/Return UX & Notifications
"As a borrower, I want clear step-by-step guidance and alerts for pickup and return so that I can complete the swap without contacting the organizer."
Description

End-to-end borrower and lender flows that enable contactless swaps: clear locker location, entry instructions, and access method; live status cards (code active, time remaining, compartment number); and simple return checklists. Sends timely push/SMS/email alerts for code activation, impending expiry, successful unlock/return, and overdue reminders. Supports multilingual content, accessibility standards, and map deep links. Integrates with Sharehood’s smart scheduling to auto-adjust instructions when booking windows shift.

Acceptance Criteria
Status Card and Activation Notifications
Given a confirmed locker booking with start time T and an ephemeral access code tied to the window When the booking window starts Then the borrower receives push, SMS, and email within 10 seconds containing compartment number, locker location label, and a secure code reveal action And the in-app status card displays "Code active", a live countdown to end time, compartment number, and access method (Bluetooth/code/Ghost PIN) And the access code is not fully revealed before T and becomes valid exactly at T And a Ghost PIN is generated and revealed only after biometric or device PIN verification for offline/backup access Given notifications are disabled for a channel When T occurs Then only enabled channels are sent; disabled channels are not sent
Map Deep Link and Entry Instructions
Given a booking with locker GPS coordinates and entry instructions When the borrower taps "Open in Maps" Then the device's default maps app opens via deep link to the coordinates with a label and walking directions from current location And if no maps app is available, an in-app map view opens with the pin and turn-by-turn steps Given intermittent connectivity When the borrower opens the status card Then the locker address, instructions, and a map snapshot render from cache within 2 seconds
Auto-Adjust Instructions on Window Shift
Given the smart scheduler shifts the booking window by Δt When the shift is saved Then the borrower and lender receive updated push, SMS, and email within 30 seconds reflecting new start/end times, code activation time, and pickup/return windows And the status card countdown, activation time, and any time-stamped instruction tokens update in-app within 5 seconds of app foreground or push receipt And any previously issued access codes are invalidated immediately and replaced; the new code is not valid before the new start time Given overlapping bookings cause an earlier pickup window When the system advances T by up to 30 minutes Then instructions auto-update without manual editing; no stale times remain in UI or notifications
Unlock Event Logging and Notification
Given the borrower uses Bluetooth, access code, or Ghost PIN to open the locker When an unlock occurs Then an audit record is created within 3 seconds with UTC timestamp, booking ID, locker ID, compartment, access method, user pseudonymous ID, and device OS; records are immutable And the borrower and lender receive a push confirming "Locker opened" within 10 seconds And the status card shows "Unlocked at [time]" and offers "View return checklist" Given an unlock attempt outside the active window When the borrower tries an expired code Then access is denied; an alert is shown; and a security log entry records the failed attempt
Return Checklist and Deposit Auto-Release
Given a booking with a deposit hold When the borrower initiates Return in-app Then the app presents a 3-step checklist: confirm item condition, place item, relock compartment; with optional photos (min 1, max 5) And after relock detection or lender confirmation, the system marks the booking "Returned", sends push/SMS/email to both parties, and submits deposit release to Stripe within 2 minutes Given relock is not detected within 60 seconds of checklist completion When the borrower submits photos showing a locked door Then the booking enters "Pending verification" and the deposit hold is retained; the lender is prompted to verify Given the return is successful When Stripe confirms release Then the status card updates to "Deposit released" within 10 seconds and an email receipt is sent
Overdue Reminder Escalation
Given end time passes without a recorded return When T+5 minutes occurs Then the borrower receives push, SMS, and email overdue reminders; the status card displays "Overdue" with options "Extend" and "Message lender" Given continued non-return When T+30 minutes occurs Then a second reminder is sent to the borrower; the lender receives a notification; and a policy link for late fees (if enabled) is included Given no action by the borrower When T+24 hours occurs Then a support ticket is created and both parties are notified; subsequent reminders pause Given the borrower purchases an extension When the extension is confirmed Then all overdue reminders are canceled and the status card reverts to an active countdown
Internationalization and Accessibility Compliance
Given device locale is a supported language (e.g., en, es, fr) When the borrower views the status card or receives notifications Then all UI strings and templates render in that locale with correct pluralization, date/time formats, and numerals across push, SMS, and email Given an unsupported locale When the borrower views the UI Then content falls back to English and the user can switch language in settings with immediate effect without app restart Given a user relying on assistive technologies When navigating the zero-contact flows Then all actionable elements are screen-reader and keyboard accessible with descriptive labels; status changes are announced via live regions; color contrast ratio >= 4.5:1; tap targets ≥ 44x44 points; and dynamic text scaling up to 200% preserves layout without loss of content or functionality Given images or diagrams in entry instructions When rendered Then alt text is present and announced by screen readers
Automated Deposit Release & Dispute Workflow
"As a lender, I want deposits to release automatically when items are returned in time and intact so that I don’t have to manage payments manually."
Description

Workflow that auto-releases Stripe deposit holds upon confirmed return based on trusted signals (locker relock event, on-time window, optional photo check-in) and configurable grace periods. Handles exceptions (late return, damage claims, no-shows) with one-click dispute initiation, evidence upload (photos, access logs), time-boxed resolution steps, and partial/total charge capabilities. Fully reconciles financial events with booking records and audit logs, and communicates outcomes to both parties.

Acceptance Criteria
Auto-Release on Confirmed Return (Locker Relock Within Window)
Given a booking with an active Stripe deposit authorization and a defined return window end time T with grace period G And a relock event from the paired locker is received and correlated to the booking within T + G And, if photo check-in is required, at least one photo is present with timestamp within the booking window and file integrity verified And there is no open dispute or late flag on the booking When the system validates these signals Then it releases the Stripe deposit hold within 2 minutes of validation And records an audit event containing booking_id, stripe_payment_intent_id, locker_event_id, release_reason = "auto_release", performed_by = "system", and timestamp And updates booking status to "Returned" and sends confirmation to borrower and lender via in-app and email within 1 minute
Grace Period Configuration and Resolution
Given an organization default grace period G_org and an optional listing override G_list When a booking is created Then the effective grace period G_eff = G_list if present else G_org is stored on the booking and in the audit log And G_eff is displayed to both parties on the booking details When a return signal is evaluated Then late vs on-time determination uses T + G_eff boundaries (inclusive of exactly T + G_eff) And any admin change to G_org or G_list applies only to bookings created after the change; existing bookings retain their stored G_eff
Late Return Flag and Auto-Release Suspension
Given no valid return confirmation has occurred by T + G_eff When the system timer elapses Then the booking status transitions to "Late" and auto-release is suspended And the current deposit authorization is preserved until its Stripe expiry (no capture or release occurs automatically) And both parties are notified with one-click actions: borrower "I Returned" (submit proof) and lender "Report Issue" And if a qualified relock event (and required photo, if configured) is received within 48 hours and no dispute has been opened Then the system clears the "Late" flag and releases the deposit as per auto-release rules And all state changes are captured in the audit log with timestamps
One-Click Dispute with Evidence Upload and SLA
Given a booking with an active or pending deposit release When either party selects "Start Dispute" and chooses a reason (late, damage, missing components, other) And uploads evidence (1–10 photos, each ≤10 MB; optional notes; auto-attached access log excerpt for the booking; optional borrower/lender chat transcript excerpt) Then the system opens a dispute, pauses any auto-release, and sets a response SLA of 48 hours for the counterparty And both parties can add timestamped evidence until the decision point; edits create new versions without overwriting prior evidence And upon resolution, the decision supports outcomes: full release, partial capture (amount specified), or full capture (not exceeding deposit) And capture/refund actions are executed within 2 minutes of decision and outcomes are communicated to both parties with rationale and evidence summary
Partial/Total Charge Execution and Financial Reconciliation
Given a dispute or policy outcome specifying a charge amount A where 0 ≤ A ≤ deposit_amount When executing the financial action Then the system captures A against the original Stripe authorization (if available) and releases the remaining authorization amount (deposit_amount − A) And creates booking-linked ledger entries for: deposit_authorized, amount_captured = A, amount_released = deposit_amount − A, currency, fees, actor, and timestamps And enforces idempotency using a stable key per outcome so retries do not duplicate captures or releases And verifies reconciliation invariant: deposit_authorized = amount_captured + amount_released And stores Stripe identifiers (payment_intent_id, charge_id/refund_id) on the booking and audit log
No-Show Determination Using Access Signals
Given the pickup window has ended and a 15-minute buffer has elapsed And no successful unlock or valid Ghost PIN usage is recorded for the borrower during the pickup window And the lender did not cancel or mark the item unavailable When the system evaluates the booking Then it marks the booking as "Borrower No-Show" and captures a configured no-show fee F (fixed or % capped at deposit_amount), releasing any remaining deposit authorization And sends outcome notifications to both parties including fee amount, reason, and an access-log excerpt as evidence And if access signals indicate the lender failed to provision access (no code activation or locker availability), then classify as "Lender No-Show", release the deposit in full, capture no fee, and notify both parties accordingly
Idempotent Handling of Multiple Return Signals
Given multiple return signals (e.g., locker relock, photo check-in, manual "I Returned") arrive within a short interval and are processed concurrently When the system evaluates release eligibility Then exactly one deposit release action is executed and subsequent attempts become no-ops referencing the processed release event id And Stripe is called at most once for the release/capture operation And only a single set of ledger and audit entries is created, preventing duplicate financial or state changes
Failure & Fallback Handling (Offline, Low Battery, Lockouts)
"As a borrower, I want reliable fallbacks if the locker is offline or low on battery so that I can still complete my pickup or return."
Description

Resiliency features to ensure successful swaps despite device or network issues: cached short-lived offline unlock via Ghost PIN, configurable attempt limits and temporary lockouts, remote unlock requests when cloud is reachable, and clear borrower messaging for each failure mode. Continuous battery and health monitoring with alerts to organizers, escalation paths (backup key instructions, support contact), and safe reissuance/rotation of credentials after failures. All exceptions are captured in the audit trail.

Acceptance Criteria
Organizer Device Provisioning & Management Console
"As an organizer, I want a simple console to provision and monitor lockers so that I can manage deployments across buildings with minimal effort."
Description

Admin console to register and verify devices, assign them to properties/items, configure access schedules and quiet hours, define pickup/return buffers, and map compartments. Displays fleet health (battery, connectivity, firmware), supports bulk import, firmware update scheduling, and per-device policy overrides. Provides quick views of active bookings per device and one-click export of access logs for HOA/tenant board reporting.

Acceptance Criteria

Cam‑Free Proof

Low‑light verification that replaces photos with an NFC/QR tap plus motion‑signed device handshake inside the geofence. Confirms pickup/return without flashes or camera use, then issues a secure receipt for both parties. Speeds silent swaps, respects privacy, and keeps deposit releases fast even in dark corridors.

Requirements

Geofenced Tap/Scan Check-in
"As a borrower, I want to confirm pickup or return by tapping or scanning within the pickup area so that I can complete the swap quickly and privately without using my camera."
Description

Implement a geofence around designated pickup/return locations that enables a context-aware “Verify Pickup”/“Verify Return” action only when a user is within the allowed radius and time window. Verification is completed via an NFC tag tap on the item/cubby or a QR code scan, mapped to the booking and item IDs. The system validates booking status, grace periods, and overlapping smart windows, then records a timestamped event with geofence ID and hashed device identifier while collecting no photos. Clear, low-light-friendly UI provides haptic feedback and concise error states (too early/late, out of zone, invalid booking), and successful events advance the booking state to trigger notifications and downstream flows (receipt issuance, deposit logic).

Acceptance Criteria
Motion-Signed Proximity Handshake
"As a lender, I want cryptographic and motion-based proof of physical presence during verification so that I can trust pickups and returns without requiring photos."
Description

Augment tap/scan with a cryptographic, motion-signed handshake to prove in-hand proximity and prevent relay/replay attacks. During verification, the app captures a short burst of accelerometer/gyroscope data and signs a server-provided nonce with a device-bound key (Secure Enclave/Android Keystore). The payload includes NFC tag UID or QR token, motion digest, timestamp, and optional RSSI, all time-boxed (≤30s freshness) and size-limited for privacy. The server validates signature, freshness, and expected motion profile before accepting the event. Fallback for QR uses a rotating signed token plus motion digest. No photo or ambient imagery is collected at any point.

Acceptance Criteria
Offline Token & Deferred Sync
"As a borrower in a low-connectivity hallway, I want verification to work offline so that my pickup or return still counts and my deposit isn’t delayed."
Description

Enable verification in low-signal corridors by supporting offline proofs. The app pre-fetches challenge material when a session starts, then, at tap/scan time, generates a signed proof (tap/scan data + motion digest + nonce) and stores it locally with a visible confirmation to both parties. When connectivity resumes, the client syncs the proof to the server for validation and booking state transition. Conflict handling prevents duplicate or out-of-order claims, and UI clearly indicates pending vs. confirmed status. Proofs expire if not synced within a defined window, with user prompts to retry. Data is minimized and encrypted at rest until upload.

Acceptance Criteria
Secure Dual-Sided Receipts & Audit Trail
"As an organizer, I want verifiable receipts and an audit trail so that I can resolve disputes quickly while protecting user privacy."
Description

Upon successful server validation, issue tamper-evident receipts to both parties, containing booking ID, item ID, event type (pickup/return), timestamp, geofence ID, verification result, and a short verification code. Deliver receipts in-app and via email/SMS with deep links for reference. Maintain an immutable, filterable audit trail for organizers that supports search, export, and scoped access while redacting PII and hashing device identifiers. Receipts and logs adhere to retention policies and can be presented during disputes without exposing location history beyond the geofence event.

Acceptance Criteria
Payment Hold Automation (Stripe Integration)
"As a borrower, I want my deposit released immediately after a verified return so that my funds aren’t held longer than necessary."
Description

Connect verification events to deposit holds to keep releases fast and reliable. On pickup verification, confirm or adjust the existing Stripe authorization per policy; on return verification, immediately release the hold or capture fees for late/damage per configured rules. Implement webhook-driven, idempotent state changes with retries, reconciliation for timeouts or offline proofs, and clear in-app status messaging (e.g., Hold Active, Release Pending, Released). Admin tools surface exceptions for manual review with audit links to the underlying verification event.

Acceptance Criteria
Cross-Device Compatibility & Fallbacks
"As a borrower with an older phone, I want a secure QR fallback if my device lacks NFC so that I can still verify pickups and returns."
Description

Provide broad device support with a seamless hierarchy: NFC tap (NDEF/Tag UID) on supported devices; QR scan fallback with rotating, signed codes for devices without NFC. Implement OS-specific permission flows, dark-mode and low-light-friendly UI, large touch targets, haptic confirmations, and localized copy. Support background NFC reading where permitted, and handle minimum OS versions gracefully. Ensure the same security posture across NFC and QR by enforcing rotating tokens, motion digests, and short validity windows.

Acceptance Criteria
Geofence Configuration & Drift Tolerance
"As an organizer, I want to configure reliable geofences that work indoors so that verification succeeds consistently without requiring cameras."
Description

Offer organizer tools to configure precise geofences per pickup point with adjustable radius, indoor-friendly heuristics (Wi‑Fi/BLE assistance where available), and drift tolerance to reduce false negatives in dense urban buildings. Support temporary curbside windows and multi-entry buildings via multiple geofence zones tied to the same asset. Include test mode and diagnostics (live location accuracy, expected zone) to validate setup before go-live, with analytics on failure reasons to continuously tune thresholds.

Acceptance Criteria

Pulse Match

Instant alerts when neighbors search for items you own—especially dormant listings. Each ping shows live demand, nearby distance, and next best pickup windows; tap once to relist using your last settings. You revive circulation in seconds, helping projects start on time while boosting your lending yield.

Requirements

Real-time Search-to-Owner Alerts
"As an item owner, I want to receive instant alerts when someone nearby searches for something I own so that I can relist quickly and capture the demand."
Description

Stream search events in real time and match them against owners’ inventories within the owner’s neighborhood/HOA boundary to trigger instant alerts. Implement an event pipeline that deduplicates near-identical queries, enforces frequency caps, and filters by eligibility (owner active, item shareable, within service radius). Deliver notifications via push and in-app first, with email fallback. Each alert payload includes item matched, query term, demand signal summary, distance band to nearest searcher, and a deep link CTA to relist. Integrate with Search Service (event emit), Inventory (ownership and item state), Geolocation (distance banding), Notification Service (multi-channel delivery), and Feature Flags (gradual rollout). Expected outcome: owners become aware of live demand within seconds, lifting reactivation rates and reducing time-to-availability for borrowers.

Acceptance Criteria
Dormant Listing Prioritization
"As an item owner with idle gear, I want dormant items prioritized in alerts so that I can easily revive listings that aren’t currently earning."
Description

Identify dormant items (e.g., no bookings or listing inactivity for N days) and bias Pulse Match to favor alerts for these items when relevant searches occur. Implement a dormancy score per item using last listed date, last booking date, and view activity; incorporate it into the alert eligibility/ranking logic so dormant items are surfaced first. Provide configurable thresholds via admin settings and exclude items the owner intentionally paused. Integrate with Analytics (activity signals), Inventory (item states), and Ranking Service. Expected outcome: previously idle gear is revived first, increasing circulation and overall marketplace liquidity.

Acceptance Criteria
One-tap Relist with Prefilled Settings
"As an item owner, I want to relist from an alert with my previous settings prefilled so that I can make my item available in seconds."
Description

Enable a single-tap relist flow from the alert deep link that opens a prefilled publish sheet using the owner’s last saved settings for that item (price, deposit hold configuration, pickup location, photos, description, category, and availability template). Allow optional quick edits, then publish in one confirmation. On publish, update the item’s calendar, re-enable Stripe deposit holds per the previous configuration, and set the listing to discoverable. Integrate with Listing Service (create/update), Calendar (availability templates), Payments (Stripe hold settings), and Notifications (success toast). Expected outcome: reactivation takes seconds, reducing owner friction and increasing response to demand pings.

Acceptance Criteria
Smart Pickup Window Suggestions
"As an item owner, I want suggested pickup windows that fit my schedule so that I can publish availability without manual calendar work."
Description

Generate next-best pickup windows at alert time and in the relist sheet by combining the owner’s availability calendar, typical loan durations for the item category, and the searcher’s desired timeframe signals. Auto-adjust windows to avoid overlaps, travel times, holidays, and quiet hours. Present 2–3 suggested windows the owner can accept as-is or tweak. Integrate with Calendar (owner availability and conflicts), Logistics Service (travel time estimates within neighborhood radius), and Time/Locale (DST, locale formatting). Expected outcome: owners publish with realistic pickup slots that minimize scheduling friction and reduce no-shows.

Acceptance Criteria
Demand and Proximity Scoring in Alerts
"As an item owner, I want to see how close and how strong the demand is so that I can judge if it’s worth relisting right now."
Description

Compute and display concise demand and proximity signals in each alert to help owners decide whether to relist. Demand score aggregates real-time search volume, recent bookings for similar items, and local supply scarcity; proximity shows a distance band to the centroid of active searchers. Present as a simple badge (e.g., “High demand • ~0.4 mi”) and include trend arrows when demand rises. Integrate with Analytics (search/bookings), Similarity/Taxonomy (similar items), and Geolocation (distance banding). Expected outcome: clearer decision context drives higher alert-to-relist conversion.

Acceptance Criteria
Notification Preferences and Quiet Hours
"As an item owner, I want to control when and how often I’m alerted so that I stay informed without being overwhelmed."
Description

Provide granular owner controls for Pulse Match: enable/disable feature, choose channels (push, email, SMS where available), set quiet hours, daily alert caps, and snooze per item or per query theme. Reflect settings in the server-side delivery policy so caps and quiet hours are enforced even if clients are offline. Add a settings screen entry under Notifications and quick actions from an alert (e.g., “Snooze 24h”). Integrate with User Settings Service, Notification Service (policy enforcement), and Experiments (default configurations). Expected outcome: high signal, low noise experience that sustains engagement without alert fatigue.

Acceptance Criteria
Privacy-safe Matching and Anti-spam Controls
"As a privacy-conscious owner, I want my alerts to protect everyone’s identity and avoid spam so that I feel safe enabling Pulse Match."
Description

Protect user privacy and system integrity in Pulse Match. Match on anonymized/hashed search tokens and do not reveal searcher identity or exact coordinates in alerts; show only coarse distance bands. Enforce rate limiting per owner, per item, and per query theme; implement deduplication windows and suppression lists for repeated alerts. Add abuse detection (suspicious search bursts, bots) and consent management (opt-out from being matched). Maintain audit logs, configurable data retention for search events, and compliance with GDPR/CCPA requests. Integrate with Privacy/Compliance services, Security (rate limiters), and Analytics (abuse heuristics). Expected outcome: trust-preserving alerts that are informative yet safe, with minimal spam risk.

Acceptance Criteria

Demand Slots

Pre-filled pickup windows generated from your past handoff patterns, building quiet hours, and current search spikes. Confirm in one tap and your calendar auto-updates, minimizing coordination and maximizing successful, on-time handoffs. Lenders save time; borrowers see slots that actually fit their schedules.

Requirements

Predictive Slot Generation Engine
"As a lender, I want pre-filled pickup windows that reflect my past handoffs, building quiet hours, and current demand so that I can confirm availability in one tap without back-and-forth."
Description

Generate pre-filled pickup windows per item and lender using historical handoff patterns, building-level quiet hours/rules, and real-time neighborhood search spikes. The engine should rank and compose time windows with configurable durations and travel buffers, respect lender time preferences and time zones, and exclude periods blocked by quiet hours or personal calendar conflicts. Provide an API to produce top-N suggested windows, explainability metadata (why a window was suggested/filtered), and controls to tune aggressiveness and minimum lead time. Support per-building rules, holidays/exceptions, and opt-in privacy controls for using behavioral data. Emit events for analytics and continuous model tuning; recalculate within sub-second latency when demand signals or calendars change.

Acceptance Criteria
One-Tap Confirmation & Batch Approvals
"As a lender, I want to approve suggested pickup windows in one tap or batch so that I can publish availability quickly and consistently."
Description

Provide a streamlined UI on mobile and web for lenders to review and publish suggested windows with a single tap, including batch approve/decline/edit for multiple items or dates. Surface conflicts, quiet-hour violations, and demand indicators inline with quick fixes (shift by +/−15 minutes, change duration, add buffer). Include undo, autosave drafts, accessibility compliance, and localized time formatting. Confirming a window triggers calendar blocking, borrower slot surfacing, and notification pipelines. Persist decisions to improve future suggestions.

Acceptance Criteria
Calendar Sync & Auto-Blocking
"As a lender, I want confirmed pickup windows to sync to my calendar automatically so that I avoid double booking and keep my schedule accurate."
Description

On confirmation, automatically block the selected windows in Sharehood’s internal calendar and optionally sync to external calendars (Google, Apple, Outlook) via OAuth with granular permissions. Support one-way push and read-only pull for conflict detection, time zone awareness, recurring events, and deduplication. Handle updates, cancellations, and reschedules with idempotent webhooks and retries. Expose an iCal feed per lender and per item, and provide conflict warnings before confirmation. Ensure privacy controls and clear labeling of synced events.

Acceptance Criteria
Quiet Hours & Building Rule Compliance
"As an organizer, I want building quiet hours automatically enforced on suggested pickup windows so that handoffs respect community rules and reduce complaints."
Description

Model and enforce building-level quiet hours and handoff rules at the address level. Allow organizers to define defaults and exceptions (holidays, move-in days, blackout dates), with lender-level overrides where permitted. The slot generator must avoid disallowed times, explain exclusions to users, and suggest compliant alternatives. Provide an admin interface for rule management and audit logs of changes. Ensure location validation ties a lender to the correct building profile and that updates propagate to existing suggestions safely.

Acceptance Criteria
Borrower-Facing Smart Slot Surfacing
"As a borrower, I want to see pickup windows that align with my schedule so that I can book quickly without coordinating messages."
Description

Display only viable, lender-approved pickup windows to borrowers during search and booking, filtered by the borrower’s time preferences, time zone, and proximity. Highlight recommended fits based on the borrower’s past pickup patterns and indicate alternative nearby times when a chosen slot is nearly full. Integrate Stripe deposit holds at booking, show clear cutoffs and buffers, and gracefully degrade to “request a time” if no suitable slots exist. Optimize for fast selection with clear statuses (open, limited, full), skeleton loading, and performance targets under 200 ms server response.

Acceptance Criteria
Overlap Resolution & Auto-Adjust
"As a lender, I want overlapping pickup windows to auto-adjust when multiple borrowers book so that I avoid conflicts without manual rescheduling."
Description

Automatically detect and resolve overlaps across a lender’s items and bookings by reflowing suggested windows, applying minimum buffers, and offering fair allocation rules (first-come-first-served with hold windows, or demand-weighted). On booking or cancellation events, recompute remaining slots within one second and notify affected users of adjustments. Support concurrency-safe locking, audit trails, and configurable caps on simultaneous handoffs. Provide simulation tools to preview the impact of changes before publishing.

Acceptance Criteria

Demand Heat

A neighborhood heatmap and top-requests board that highlights which dormant items will book fastest this week. One-tap relist buttons sit right on the hotspots, so you activate the most-wanted gear first. Spend minutes, not hours, to keep your library in steady circulation.

Requirements

Real-time Demand Signal Aggregation
"As an organizer, I want neighborhood-level demand signals combined into a single, current score so that I can quickly see what items will book fastest this week without manually crunching data."
Description

Implement a backend service that continuously ingests, normalizes, and aggregates demand signals per neighborhood and category to power the Demand Heat feature. Signals include searches, wishlists, item page views, failed/abandoned booking attempts, messages requesting items, and recent booking velocity. Data is windowed to “this week,” decay-weighted for freshness, and normalized by neighborhood population and active user base. The service outputs per-cell and per-item demand scores via a versioned API consumed by the heatmap and the Top Requests board. It enforces privacy by k-anonymity thresholds and de-identification before exposure, filters bots/fraud, and respects HOA/tenant boundary scoping. It supports near-real-time refresh (≤5 minutes), backfill jobs, and resilience with idempotent event processing, retries, and monitoring. Caching and rate limiting ensure predictable latency and cost. Instrumentation provides observability and A/B segmentation hooks.

Acceptance Criteria
Neighborhood Heatmap Visualization
"As a resident, I want a clear heatmap of where demand is highest around me so that I can quickly decide which of my items to relist first."
Description

Deliver an interactive map overlay that visualizes demand intensity by cell (e.g., hex/bin tiles) for the user’s neighborhood. The map supports dynamic zoom levels, color gradients with accessible contrast, and tappable hotspots that reveal the top-requested items and context-aware actions. Cells obey privacy thresholds (no render below k requests) and adhere to HOA/neighborhood boundaries. Performance targets include sub-300 ms tile fetches and smooth pan/zoom at 60 fps through tile caching and prefetching. The map integrates with user identity to highlight hotspots where the user owns matching dormant items and provides in-context relist CTAs. Works on web and mobile with graceful degradation to the Top Requests board if location or map services are unavailable.

Acceptance Criteria
Top Requests Board
"As a library organizer, I want a ranked board of top requests this week so that I can activate dormant inventory without digging through multiple reports."
Description

Create a list-based board that ranks the top requested items in the selected neighborhood for the current week. The board supports filters (category, timeframe), sorting (demand score, projected bookings), and owner-specific cues (e.g., “You own this—relist now”). It displays estimated booking probability, suggested price and deposit ranges, and reason codes (e.g., recent searches, failed bookings) for transparency. The board acts as a non-map fallback and deep-links from heatmap hotspots. Organizers can switch to a library-wide view to see dormant items across members. Fast-loading API-driven UI with pagination and empty-state messaging for low-signal neighborhoods.

Acceptance Criteria
One-Tap Relist Actions
"As an item owner, I want to relist a recommended item with one tap so that I can keep my gear circulating without spending time rebuilding listings."
Description

Enable in-context, minimal-friction relisting from hotspots and the Top Requests board. Prefill listing details from prior listings (title, photos, category, tags), propose smart pickup windows that avoid calendar conflicts, and recommend pricing and deposit holds based on demand data and historical performance. Support batch relist (multi-select) and confirmation in ≤2 taps. Validate item availability, enforce HOA rules, and integrate with Stripe to ensure deposit hold settings are applied. Provide optimistic UI with robust error handling, audit logs, and success telemetry to attribute bookings to Demand Heat.

Acceptance Criteria
Book-Fast Scoring Engine
"As a time-constrained owner, I want a clear score showing which of my dormant items are most likely to book this week so that I can prioritize relisting with confidence."
Description

Build a scoring service that estimates the “will book this week” probability per item/category within a neighborhood. Start with a heuristic (e.g., weighted combination of searches, failed bookings, recent velocity, seasonality) and optionally progress to a simple ML model for calibration. Provide explanation snippets (top contributing factors) and confidence bands for transparency. Scores are versioned, refreshed at least daily (ideally every 5 minutes for aggregates), and exposed through the aggregation API. Safeguards include caps for data sparsity and fallbacks in low-signal areas. Include offline evaluation, backtesting, and guardrails to prevent over-promotion of niche or policy-restricted items.

Acceptance Criteria
Demand Alerts & Deep Links
"As a busy resident, I want concise alerts with direct relist links so that I can act on high-demand opportunities without checking the app daily."
Description

Provide opt-in weekly (and optional high-signal) notifications via push/email summarizing top relist opportunities in the neighborhood. Messages include deep links that open the app directly on the relevant hotspot or item with prefilled relist settings. Users control frequency, quiet hours, and categories of interest. Compliant with GDPR/CCPA consent and easy unsubscribe. Instrumented with campaign identifiers for attribution to bookings and relists. Fallback digest available in-app for users who decline notifications.

Acceptance Criteria

Price Nudge

Smart, transparent guidance that suggests a booking-friendly price and deposit based on similar items, seasonality, and recent fill speeds. See the projected impact before you confirm. Relist with confidence, reduce idle time, and stay fair to neighbors.

Requirements

Comparable Item Matching Engine
"As an owner listing an item, I want the system to find the closest comparable items in my area so that the suggested price reflects real local demand and fairness."
Description

Identify and score the most relevant comparable listings to each item using category, subcategory, brand/model, condition, age, accessories, replacement value, owner rating, and typical booking duration. Limit comps to a configurable local radius and time window, filter outliers and stale data, and weight by proximity and recency. Provide a real-time service that returns a ranked comp set with normalized price and deposit metrics, confidence scores, and fallback strategies when data is sparse (neighborhood → city → platform-level). Integrate with Sharehood’s catalog, calendar availability, and booking history while preserving user privacy and honoring opt-outs. Expose an internal API consumed by Price Nudge and instrument with observability to monitor coverage and quality.

Acceptance Criteria
Seasonality & Local Demand Modeling
"As an owner, I want seasonal and local demand to be factored into the price suggestion so that my item stays competitive during peaks and doesn’t sit idle during slow periods."
Description

Generate category- and neighborhood-specific demand multipliers that adjust suggested prices and deposits for day-of-week, week-of-year, and local holidays/events. Train models on historical search views, booking requests, acceptances, and fill times, with decay weighting for recent trends and safeguards for data sparsity. Update factors on a weekly cadence, support overrides for known events (e.g., moving weekends, storm forecasts), and expose an API that returns a demand factor and confidence interval for a given time window. Integrate with Price Nudge to apply the factor transparently in the rationale and preview, and log versions for auditability and rollback.

Acceptance Criteria
Fill-Speed Driven Price Optimization
"As an owner who wants my item booked quickly, I want a price that balances speed and fairness so that I reduce idle time without underpricing."
Description

Estimate the relationship between price and expected time-to-book for each item by combining comparable listing data, seasonality factors, and the owner’s historical acceptance behavior. Optimize for a default target (e.g., book within 72 hours) with the ability to change the target in the UI, and compute the price that maximizes booking probability subject to owner guardrails (min/max price) and community fairness caps. Output suggested price, expected days to fill, utilization impact, and confidence. Recompute suggestions on listing edits, availability changes, or new market signals, and cache results to minimize latency in the listing flow and relist modal.

Acceptance Criteria
Deposit Hold Recommendation & Stripe Compliance
"As an owner, I want a deposit recommendation that protects my item and complies with payment rules so that I can reduce risk without scaring away borrowers."
Description

Recommend a deposit hold amount aligned to item risk and replacement value while complying with Stripe capabilities and regional regulations. Incorporate incident rates by category, owner-set replacement cost, and historical claim outcomes to produce a deposit suggestion and hold window that aligns with Sharehood’s smart pickup/return times. Validate against Stripe constraints (max hold, renewal windows, SCA) and display fee or failure implications. Provide fallbacks when a hold cannot be placed (e.g., suggest lower deposit or require identity verification) and expose clear messaging in the Price Nudge rationale and preview.

Acceptance Criteria
Transparent Impact Preview
"As an owner, I want to see the expected impact of the suggested price before I confirm so that I can make an informed decision."
Description

Present an interactive preview that compares current vs. suggested price and deposit, projecting effects on booking probability, expected days to fill, weekly utilization, and acceptance rate. Display the top drivers (comps, seasonality, fill-speed) with a plain-language explanation and a link to view representative comps. Allow owners to adjust a simple goal slider (speed vs. earnings) and see projections update instantly. Ensure mobile-first, accessible UI that fits into the Listing > Pricing step and Relist flow, with analytics events to track impressions, interactions, and adoption.

Acceptance Criteria
One-Tap Apply & Auto-Adjust Guardrails
"As an owner, I want to quickly apply or auto-adjust the suggested price with safety limits so that I can relist confidently without constant manual tuning."
Description

Enable owners to apply suggested price and deposit in one tap and optionally turn on auto-adjust, which keeps pricing within owner-defined floors/ceilings and community fairness caps as market conditions change. Respect existing bookings and smart pickup windows, schedule changes for the next available slot, and provide undo and change history. Send a confirmation and notification of future auto-adjustments, and surface controls to pause or fine-tune the feature per item. Log all pricing changes for audit and support A/B testing to measure impact on fill speed and owner satisfaction.

Acceptance Criteria

Own-It Prompts

Lightweight, opt-in prompts ask if you have frequently searched items (e.g., folding tables, impact drivers) when demand spikes nearby. If you do, a 60-second flow spins up a fresh listing with suggested details and ready-to-go windows. Turn likely possessions into community utility with almost zero effort.

Requirements

Local Demand Spike Detection
"As an opted-in resident, I want the app to detect when nearby demand spikes for items I might own so that I can be prompted to list them at the right time."
Description

Identify item archetypes experiencing significant demand increases within a user’s neighborhood (e.g., HOA boundary, zip-code radius) by aggregating signals such as search frequency, wishlist adds, failed availability attempts, and shortened booking lead times. Compute rolling baselines and trigger spikes based on configurable thresholds and time windows (e.g., 24–72 hours). Produce a ranked, deduplicated feed of “high-need” items with metadata (archetype, confidence, geo radius, demand window start/end) for downstream prompt targeting. Run on a near real-time schedule with latency under 15 minutes and provide organizer overrides for manually featured items.

Acceptance Criteria
Likely Owner Targeting & Eligibility Scoring
"As an opted-in resident, I want prompts to be relevant to items I’m likely to own so that I’m not spammed with unrelated requests."
Description

Score and select recipients for Own-It Prompts using a lightweight, privacy-aware model combining heuristics (past searches, prior listings, neighborhood role, proximity to demand centroid) and optional ML signals. Enforce eligibility constraints (user is opted-in, active in the last 90 days, has not recently declined the same archetype). Provide reason codes for transparency in prompts (e.g., “Neighbors need folding tables this weekend”). Configure score thresholds and suppression rules to minimize irrelevant prompts and balance coverage with precision.

Acceptance Criteria
Opt-in Permissions & Privacy Controls
"As a privacy-conscious user, I want to opt in and control how and when prompts reach me so that I can participate without unwanted interruptions or data use."
Description

Add a clear, granular consent flow and settings panel for Own-It Prompts, including toggle to enable/disable, category preferences, quiet hours, and channel preferences. Present concise data-use disclosures (signals used, retention, purpose) and log consent with timestamp and version for audit. Support revocation, data deletion, and export consistent with GDPR/CCPA. Ensure targeting and delivery services hard-check consent state before processing, and store only the minimum data needed for prompt generation.

Acceptance Criteria
Multi-channel Prompt Delivery & Throttling
"As an opted-in user, I want timely, non-intrusive prompts with options to snooze or decline so that I stay in control while still helping my neighbors."
Description

Deliver Own-It Prompts via in-app cards, push notifications, and email with user-configurable channel preferences and local quiet-hour observance. Implement frequency caps (e.g., max 2 prompts/week, 1 per archetype/14 days), snooze and decline actions, and suppression after recent participation. Localize copy and support A/B testing for timing, messaging, and channel mix. Embed deep links that open the 60-second listing flow prefilled with the detected archetype and suggested availability. Track delivery, open, click, and conversion events end-to-end.

Acceptance Criteria
60-second Listing Composer with Smart Prefills
"As a resident who owns the item, I want a fast, prefilled listing flow so that I can publish a usable listing in under a minute."
Description

Provide a streamlined creation flow that pre-populates a new listing from the prompted archetype: suggested title, category, description template, safety notes, and default deposit-hold policy. Offer quick photo capture or stock iconography, and auto-suggest tags/accessories. Validate pickup location and show a single review screen with clear publish CTA. Ensure new listers pass required checks (e.g., account verification) and auto-link the listing to standard community policies. Target total time-to-publish under 60 seconds from prompt open.

Acceptance Criteria
Smart Availability Windows & Conflict Avoidance
"As an owner, I want the app to propose pickup and return times that fit my schedule and the surge in demand so that I don’t have to micromanage logistics."
Description

Generate suggested pickup/return windows aligned to the detected demand window and the owner’s existing Sharehood calendar, auto-adjusting to avoid overlaps and quiet hours. Provide simple edits (drag/drop blocks, time-of-day presets) and validate time zones and daylight-saving changes. If conflicts arise at publish time, auto-resolve with the next best window and clearly surface the change to the owner. Expose an API for the calendar engine to consume new availability constraints.

Acceptance Criteria
Performance Analytics & Experimentation
"As a product manager, I want to measure and iterate on Own-It Prompts so that we maximize useful listings while minimizing user fatigue."
Description

Instrument the funnel from detection to prompt delivery to listing publish, capturing metrics such as eligible users, delivery rate, open rate, prompt CTR, time-to-publish, listing conversion rate, incremental supply, booking rate, and no-show impact. Provide dashboards and alerting on key KPIs and enable feature flags and A/B testing at geo and cohort levels. Use privacy-preserving aggregation and honor user consent. Include a kill switch for rapid rollback without code deploys.

Acceptance Criteria

Pulse Digest

An optional daily or weekly summary of matches you could fulfill, ranked by projected fill rate and potential earnings. Batch-approve relists and set snooze rules to avoid notification overload. Stay responsive to neighborhood needs without constant pings.

Requirements

Opt-in Digest Scheduling
"As a lender, I want to choose when and how often I receive a consolidated digest so that I stay responsive without being interrupted throughout the day."
Description

Provide per-user controls to enable Pulse Digest with daily or weekly cadence, preferred send time, and quiet hours, with optional per-category subscription. Respect the user’s neighborhood time zone and global notification preferences; default is opt-out until explicitly enabled. A scheduler service generates digests only when qualifying matches exist, skipping sends on empty days to avoid noise. Preferences are stored per user and synchronized across devices, ensuring consistent behavior in email and in-app delivery.

Acceptance Criteria
Match Scoring and Ranking Engine
"As a lender, I want my digest ranked by likelihood to convert and potential earnings so that I can focus on the most valuable requests first."
Description

Compute a prioritized list of borrowing requests each user could fulfill, ranked by projected fill rate and potential earnings. Scoring inputs include listing availability, live calendar windows, distance/proximity, borrower reliability signals, Stripe deposit thresholds, and historical acceptance patterns. Provide explainable rankings with per-item score components and rationale. Expose a low-latency API that returns top-N candidates per user with caching and pagination, and enforce fairness and spam filters to prevent overexposure of any single requester or category.

Acceptance Criteria
Digest Composition and Personalization
"As a lender, I want a concise, personalized summary with the most relevant matches and clear reasons why they’re suggested so that I can make quick decisions."
Description

Assemble the Pulse Digest content by grouping top-ranked matches into clear sections (e.g., by category or pickup window) and including key details: projected earnings, estimated pickup windows that respect overlapping bookings, distance, deposit amount, and trust indicators. Personalize volume caps, categories, and tone based on user preferences and past interactions. Provide “why this is recommended” explanations per item, multi-language readiness, and accessible layouts. Ensure graceful fallbacks when matches are sparse, and include CTAs for quick actions.

Acceptance Criteria
Batch Actions and Quick Approvals
"As a lender, I want to batch-approve relists and confirm availability directly from the digest so that I can manage requests in minutes instead of logging into the app repeatedly."
Description

Enable one-tap and multi-select batch actions from the digest (email and in-app) to approve relists, confirm availability, or dismiss requests. Use secure, short-lived, signed deep links for email actions and native intents in-app. Ensure atomic processing with idempotency keys, conflict checks against the live calendar, and auto-adjusted pickup windows when overlaps occur. Provide an undo window and activity audit trail to recover from mistakes and maintain accountability.

Acceptance Criteria
Snooze Rules and Volume Caps
"As a busy organizer, I want to set snooze rules and caps for my digest so that I can avoid overload while still staying helpful to neighbors."
Description

Allow users to define snooze rules by category, time window, and duration (e.g., snooze all tool requests for 2 weeks), and to set maximum items per digest. Respect quiet hours and temporary pauses, with automatic resume and clear status indicators. Integrate rules into scheduling and composition services to ensure the digest never exceeds user-defined thresholds, preventing notification overload.

Acceptance Criteria
Delivery Channels and Actionable Deep Links
"As a lender, I want to receive the digest in my preferred channel with one-tap actions so that I can respond quickly from any device."
Description

Deliver Pulse Digest via email, in-app inbox, and optional push summary. Render emails in responsive HTML with text-only fallbacks and include deep links that route to item detail or execute safe quick actions using expiring tokens. Ensure device-aware formatting, retry on transient delivery failures, and compliant unsubscribe/manage-preferences controls in email footers. Track delivery status and bounce handling to maintain sender reputation.

Acceptance Criteria
Performance, Analytics, and Guardrails
"As a product owner, I want measurable insights into how the digest impacts fill rates and earnings so that we can optimize the feature and prove its value."
Description

Instrument open, click, action, and conversion events end-to-end to attribute fill rate and earnings uplift to Pulse Digest. Provide dashboards and cohort reports for product and organizers, with privacy-preserving aggregation and data retention limits. Support A/B tests on cadence, ranking weights, and layout variants. Define SLIs/SLOs for digest generation latency and delivery success, with alerts and automatic fallback behavior when services degrade.

Acceptance Criteria

Floor Caps

Set and enforce per-floor (or zone) limits on simultaneous pickups and returns, with time-of-day rules. When a slot would exceed the cap, Sharehood auto-offers staggered alternatives that fit both parties. HOA admins get one-tap overrides with auto-logged reasons, reducing hallway pileups, elevator blocking, and complaint volume while keeping bookings flowing.

Requirements

Floor/Zone Cap Configuration with Time-of-Day Rules
"As an HOA admin, I want to set per-floor caps with time-based rules so that I can prevent hallway and elevator overcrowding without pausing bookings."
Description

Provide HOA/organizer admins a configuration console to define per-floor or custom zone capacity caps for simultaneous pickups, returns, and combined total, with separate limits by day of week and time-of-day windows. Support recurring rules, exception dates (e.g., move-in days, holidays), blackout periods, and effective date ranges with versioning. Allow distinct buffers between appointments (e.g., 5–15 minutes) and a minimum stagger increment per zone to reduce elevator congestion. Expose a zone taxonomy (floor numbers, lobby, loading dock) with bulk import and validation, and map listings/units to zones. Ensure changes are previewable before publishing and applied without breaking existing confirmed bookings unless explicitly chosen by an admin.

Acceptance Criteria
Real-time Cap Enforcement on Create/Modify
"As a resident booking an item, I want the system to prevent overbooked time slots so that my pickup doesn’t get stuck in a crowded hallway or elevator."
Description

At booking creation, reschedule, or return-time changes, evaluate the requested slot against active floor/zone caps and buffers in real time, blocking confirmation if limits would be exceeded. Consider the booking’s pickup/return type, duration, zone mapping, and overlapping windows, including grace periods and existing holds. Handle concurrency safely with optimistic locking and retry to prevent race conditions during peak usage. Respect admin-approved exceptions and legacy bookings, and provide clear, actionable error states to the client. Log all enforcement decisions for auditability and downstream analytics.

Acceptance Criteria
Smart Staggered Slot Suggestions
"As a borrower, I want the app to suggest nearby times when my requested slot is full so that I can quickly complete my booking without trial and error."
Description

When a requested slot breaches a cap, automatically compute and present staggered alternative times that satisfy both the borrower’s and lender’s availability, zone caps, buffers, and travel-time constraints. Use configurable increments (e.g., 5/10 minutes) and prioritize minimal deviation from the requested time while maximizing cap compliance and flow. Rank suggestions by earliest feasible time, least disruption to both parties, and elevator load smoothing. Provide APIs and UI components that return 3–5 top suggestions with clear rationales ("avoids elevator peak at 6:00 PM"). Ensure performance under high contention, returning suggestions within sub-second targets.

Acceptance Criteria
Admin One-Tap Override with Reason Logging
"As an organizer, I want to override a cap in special situations so that urgent pickups can proceed while keeping a clear audit trail."
Description

Enable authorized HOA/organizer admins to override cap enforcement on a per-booking basis with a single action, capturing a required reason from a configurable picklist and optional notes. Automatically log the override with timestamp, admin identity, impacted zone/time, and before/after state for audit and reporting. Allow temporary override scopes (single slot, time window, or specific parties) with automatic expiration. Notify affected users of the approved exception and reflect it in calendars while preserving compliance for other bookings. Include permission checks, rate-limits, and visibility controls to prevent misuse.

Acceptance Criteria
Capacity-Aware Calendar & UI Indicators
"As a resident, I want to see which times are less crowded so that I can choose a pickup window that avoids delays."
Description

Augment calendars and slot pickers with real-time capacity visualization per floor/zone, showing available, near-capacity, and full states via color coding and accessibility-compliant labels. Surface countdowns to cap thresholds, buffer windows, and suggested staggering directly in the selection flow for borrowers, lenders, and admins. Provide quick filters by zone and peak/off-peak indicators to steer users toward less congested times. Ensure mobile-first performance and ARIA semantics so screen reader users receive the same guidance. Reflect admin overrides and rule changes instantly with cache invalidation and soft refresh.

Acceptance Criteria
Notifications for Adjustments, Overrides, and Cap Changes
"As a borrower, I want clear notifications when my booking time changes due to capacity rules so that I can adjust my plans confidently."
Description

Send timely, multi-channel notifications (in-app, push, email) when slots are auto-staggered, when admin overrides are granted or revoked, and when published cap rules affect existing bookings. Include actionable options to accept a suggested time, request another, or contact the organizer, updating ICS/calendar invites accordingly. Batch and throttle messages to prevent notification fatigue during mass rule updates, and localize content. Provide delivery status tracking and fallback channels if a primary channel fails. Ensure compliance with user notification preferences and community policies.

Acceptance Criteria
Cap Utilization Analytics & Alerts
"As an HOA admin, I want analytics on how caps are performing so that I can tune rules to minimize congestion while keeping bookings flowing."
Description

Track and report per-zone cap utilization, average wait/stagger deltas, override frequency, peak congestion windows, and conversion impact of suggestion flows. Provide dashboards for HOA admins with trendlines and heatmaps, plus CSV export and API access. Trigger proactive alerts when zones sustain high utilization (e.g., >80% for 3 consecutive days) or when overrides exceed thresholds, recommending rule tuning (increase buffer, shift caps by hour). Anonymize resident-level data and align with privacy policies. Use these insights to reduce complaints and optimize caps without harming booking throughput.

Acceptance Criteria

Flow Forecast

A forward-looking hallway and elevator load forecast that visualizes the next 48 hours by floor and common area. Color-coded guidance surfaces low-impact windows and flags impending congestion before it happens. Borrowers see ‘green’ times that fit their schedules; organizers get proactive control to smooth peaks and avoid conflict-heavy clusters.

Requirements

48-Hour Capacity Forecast Engine
"As an organizer, I want an accurate 48-hour forecast by floor and area so that I can proactively smooth peaks and prevent congestion."
Description

Compute a rolling 48-hour forecast of hallway and elevator load per floor and common area using booking data, building topology, capacity constraints, and policy buffers. Ingest Sharehood reservations, organizer calendar blocks, maintenance schedules, and known high-impact events to generate time-bucketed load scores. Normalize outputs to a 0–100 scale with configurable green/yellow/red thresholds. Refresh forecasts at least every 5 minutes and on booking changes, with timezone-aware calculations and daylight saving handling. Provide graceful degradation with baseline heuristics when data is sparse. Expose results via internal service APIs for UI, alerts, and booking suggestions, meeting performance targets (<500 ms p95 for a mid-size building).

Acceptance Criteria
Color-Coded Timeline and Floor View
"As a borrower, I want a simple visual that highlights green times that fit my schedule so that I can pick a low-impact pickup window quickly."
Description

Present forecast results in an accessible, mobile-responsive visualization that combines a timeline heatbar and per-floor/common-area view. Use clear green/yellow/red color states with WCAG-compliant contrast and patterns for color-blind users, accompanied by a legend and tooltips showing predicted load, peak drivers, and suggested low-impact windows. Include filters for floors/areas, a time scrubber, and quick-jump to next green window. Support caching for fast rendering, live auto-refresh on data updates, and localization for time and language. Integrate seamlessly with Sharehood’s borrower and organizer dashboards.

Acceptance Criteria
Smart Window Suggestions in Booking Flow
"As a borrower, I want intelligent time suggestions that avoid congestion so that I can finish booking quickly and reduce friction with neighbors."
Description

Embed forecast-aware recommendations directly into the booking and rescheduling flow. When a borrower selects a preferred time, propose the top alternative green windows within a configurable tolerance, explain the suggestion (e.g., “elevator congestion predicted 5:30–6:00 PM”), and allow one-tap accept or keep-original with a soft warning. Auto-adjust pickup/return windows to minimize overlaps, respect per-building buffer policies, and update Stripe deposit holds accordingly. Provide backend APIs to score candidate windows and frontend components with fallbacks when forecasts are unavailable.

Acceptance Criteria
Organizer Alerts and Peak Smoothing Controls
"As an organizer, I want timely alerts and controls to mitigate predicted bottlenecks so that I can keep hallways and elevators flowing smoothly."
Description

Deliver proactive alerts when predicted load crosses configurable thresholds, with channels including in-app notifications, email, and Slack/push. Offer recommended actions such as temporarily blocking red-zone windows, increasing buffer times, or sending targeted nudges to reschedule. Support bulk-reschedule suggestions with pre-filled alternatives, approval workflows, and exception handling for priority bookings (e.g., accessibility or emergencies). Provide per-area policies (quiet hours, freight elevator rules) and an audit trail of changes and overrides.

Acceptance Criteria
Building Topology and Capacity Configuration
"As an admin, I want to configure my building’s layout and capacities so that the forecast reflects real-world conditions."
Description

Provide an admin interface and APIs to define building structure and constraints: floors, hallway segments, elevator banks, capacities, service hours, holidays, move-in days, and special rules (freight-only windows). Support CSV import and template presets for common layouts. Enable versioned configurations with change history and environment-specific settings for multi-building portfolios. Enforce role-based access, validation checks (e.g., capacity ranges), and immediate propagation to the forecasting service.

Acceptance Criteria
Learning Feedback Loop and Accuracy Metrics
"As an organizer, I want the system to improve prediction accuracy over time so that congestion guidance stays trustworthy."
Description

Capture realized traffic signals from booking check-ins/outs, completion rates, and optional integrations (elevator telemetry, door counters) to evaluate forecast accuracy. Compute and display metrics (e.g., MAPE, precision/recall for red-zone flags) per building and area, identify recurring error patterns, and schedule periodic model recalibration. Include anomaly detection and guardrails to prevent spurious adjustments. Provide an A/B switch to compare current vs. baseline models and a privacy-preserving aggregation pipeline.

Acceptance Criteria
Privacy, Access Control, and Compliance Safeguards
"As a resident, I want my activity to remain private while still benefiting from congestion guidance so that I feel comfortable using Sharehood."
Description

Ensure forecasts and visualizations are aggregated and de-identified, exposing no personally identifiable information. Implement role-based views (borrower vs. organizer vs. admin), encrypted transport and storage, strict data retention, and consent controls. Maintain audit logs for policy changes and overrides, and align with relevant regulations (GDPR/CCPA) and HOA/tenant association guidelines. Provide a privacy impact assessment template and incident response playbook specific to forecasting data.

Acceptance Criteria

Elevator Sync

Pickup windows align with elevator patterns—avoiding rushes, cleaning cycles, and maintenance blocks. Bulky-item bookings are metered automatically, with estimated wait times and alternative stair-friendly micro-slots where appropriate. Result: shorter waits, fewer blocked doors, and calmer lobbies without manual coordination.

Requirements

Elevator Schedules & Blocks Ingestion
"As an HOA/tenant organizer, I want to capture and maintain my building’s elevator schedules and blocks so that Sharehood can automatically avoid conflicts when neighbors book pickups and returns."
Description

Enable per-building ingestion and management of elevator availability, including cleaning cycles, maintenance blocks, rush-hour windows, and ad‑hoc outages. Support multiple input methods: organizer UI for manual/recurring rules, calendar file import (ICS), and optional building API webhooks. Store rules in a time‑zone aware calendar model with elevator bank granularity (passenger vs service), effective dates, and priorities. Expose an internal availability service that marks blackout periods and reduces slot capacity for partial restrictions, feeding Sharehood’s live booking calendar so pickups and returns are automatically steered away from conflicts. Provide validation, conflict detection, and an audit log for changes.

Acceptance Criteria
Rush Window Prediction & Capacity Modeling
"As a resident borrower, I want accurate predictions of busy elevator periods so that I can choose pickup times with shorter waits."
Description

Model elevator traffic intensity and available throughput per time slice using historical booking outcomes, building-provided data, and heuristics (e.g., commute peaks). Produce a capacity score and expected wait-time curve per elevator bank at 5–15 minute granularity. Adjust predictions based on day-of-week/seasonality, known events, and recent real-time signals (e.g., series of delayed trips). Provide fallbacks when data is sparse. Make outputs consumable by the slot orchestrator and UI so that busy periods are automatically de-emphasized and users see data-driven wait estimates.

Acceptance Criteria
Smart Slot Orchestration & Bulky-Item Metering
"As a borrower of a bulky item, I want the system to meter and place my booking into a compliant slot so that the elevator isn’t overloaded and my trip is smooth."
Description

Allocate pickup/return slots by merging elevator availability, predicted capacity, and Sharehood’s inventory reservations to minimize lobby congestion and door holds. Enforce metering rules for bulky items (size/weight flagged in item metadata) so no slot exceeds safe elevator usage per bank; apply minimum gaps between bulky moves and prevent overlapping large-item bookings on the same bank. Respect building-specific constraints (service elevator only, quiet hours) and dynamically compute permissible micro-windows. Provide a deterministic, explainable placement engine with conflict resolution and alternative suggestions, writing final holds to the live calendar.

Acceptance Criteria
Wait-Time Estimates & Stair-Friendly Alternatives
"As a borrower on a low floor, I want stair-friendly micro-slot alternatives when it’s busy so that I can avoid long elevator waits."
Description

Surface estimated elevator wait times in the booking flow and calendar, highlighting less congested options. When items are tagged stair-friendly and user/building settings allow, offer alternative stair micro-slots with suggested timing by floor range to bypass peaks. Indicate trade-offs (e.g., carrying effort) and clearly label service vs passenger paths. Respect user preferences (avoid stairs, accessibility) and never propose stairs where prohibited. Persist selected alternative in the booking record and reflect it in organizer dashboards to prevent lobby pileups.

Acceptance Criteria
Real-Time Outage Handling & Auto-Reschedule
"As a borrower, I want immediate notifications and easy rebooking when an elevator goes down so that my pickup still happens without penalty or confusion."
Description

Monitor elevator status via organizer inputs and optional building webhooks; when an outage or new block occurs, immediately recompute affected bookings and propose compliant alternatives. Notify borrowers/lenders via push/SMS/email with one-tap confirm or pick another slot, and adjust Stripe deposit hold grace periods to avoid penalizing users for building issues. Update the live calendar, recalculate wait times, and, where safe, offer stair micro-slots. Maintain an incident timeline and post-mortem metrics (rebook rate, average delay) for organizers.

Acceptance Criteria
Per-Building Config, Accessibility & Safeguards
"As an organizer, I want configurable rules and accessibility safeguards so that bookings respect building policies and residents’ needs without manual coordination."
Description

Provide an admin console for organizers to configure elevator banks, service-elevator-only policies, weight/size thresholds for bulky items, quiet hours, cleaning windows, and stair usage rules. Allow residents to set accessibility preferences (e.g., cannot use stairs), which are enforced across suggestions and orchestration. Include guardrails such as maximum concurrent bookings per lobby, minimum gaps between door-hold events, and per-floor pacing. Log decisions and rule hits for transparency, and ensure privacy by scoping data to the building and masking personally identifiable information in operational dashboards.

Acceptance Criteria

Zone Waves

Divide the building into micro‑zones (wings, stacks, or towers) and release windows in alternating waves so adjacent areas aren’t active at once. Clear wave countdowns keep residents informed, while the system auto-shifts new requests to the next wave. This evens out traffic and keeps corridors navigable.

Requirements

Zone Definition & Adjacency Mapping
"As an organizer, I want to define micro‑zones and their adjacencies so that wave scheduling can separate nearby traffic and keep corridors clear."
Description

Enable organizers to create and manage micro‑zones (e.g., wings, stacks, towers) with metadata such as names, floors, capacity, pickup drop points, and adjacency links. Provide admin UI and APIs to define adjacency graphs, import/export zone data (CSV), and version changes with audit logs. Persist zones at building and portfolio levels, integrate with Sharehood’s calendar and inventory so bookings are aware of zone context, and support validation to prevent orphaned or overlapping zone definitions.

Acceptance Criteria
Wave Scheduling Engine
"As an organizer, I want waves to release in alternating windows across zones so that resident pickups are staggered and hallways aren’t congested."
Description

Generate alternating release windows per zone using configurable cadence (e.g., 15/30/60 minutes), offsets, and buffer times that ensure adjacent zones are not active concurrently. Enforce per‑zone concurrency limits, elevator/corridor buffers, and building‑level templates. Recompute schedules on zone changes and daylight savings shifts, write blocks to the Sharehood booking calendar, and expose availability via API for the booking flow.

Acceptance Criteria
Auto‑Shift to Next Eligible Wave
"As a resident, I want my request to be moved to the next available wave automatically so that I don’t have to manually search for a valid pickup time."
Description

Automatically reassign booking requests that fall into blocked or conflicting windows to the next eligible wave based on zone rules and user constraints. Preserve cart context, show the new pickup window inline, and require a one‑tap confirmation with an option to choose another time. Coordinate Stripe deposit hold timing with the new window, record reschedule events, and respect accessibility preferences (e.g., longer buffers).

Acceptance Criteria
Wave Countdown & Resident Notifications
"As a resident, I want clear countdowns and alerts for my zone’s wave so that I know exactly when to pick up without waiting in the hallway."
Description

Display real‑time countdown timers for each zone’s upcoming wave across item pages, booking confirmation, and a building status screen. Send push/email alerts when a resident’s zone is about to open or when a booking is shifted. Implement WebSocket/SSE updates for live accuracy, accessible color/contrast and text alternatives, localization, quiet hours, and per‑user notification preferences.

Acceptance Criteria
Traffic Load Balancing Rules
"As an organizer, I want configurable traffic limits and auto‑throttling so that building corridors remain navigable during peak times."
Description

Apply a rules engine that uses the adjacency graph, corridor/elevator constraints, and historical throughput to cap concurrent pickups per wave and dynamically throttle during surges. Support emergency pauses for specific zones, temporary capacity reductions, and automatic redistribution across future waves. Provide analytics to tune cadence and capacity and ensure rules comply with building safety policies.

Acceptance Criteria
Admin Controls & Safe Overrides
"As an organizer, I want real‑time controls and safe overrides so that I can resolve unexpected traffic or service events without breaking the schedule."
Description

Provide organizer dashboards to pause/resume zones, advance/defer a wave, create one‑time exceptions, and force‑move bookings with user notifications. Include role‑based permissions, bulk actions for multi‑building portfolios, impact previews, rollback, and guardrails against violating adjacency constraints. All actions are audited and changes propagate in real time to calendars and countdowns.

Acceptance Criteria

Buffer Bands

Automatic pre‑ and post‑window buffers that adapt to item size, distance to the elevator, and current building load. Bands expand during busy times and compress when traffic is light, preventing doorway overlap and elevator bottlenecks. Everyone gets predictable, stress-free handoffs without back-and-forth messaging.

Requirements

Dynamic Buffer Computation
"As a borrower, I want pickup and return windows that adapt to my building’s traffic and the item size so that handoffs are predictable and I avoid elevator conflicts."
Description

Compute adaptive pre- and post-handoff buffers per booking using item size class, distance from unit to elevator/exit, and current building load. Apply configurable min/max caps, round to friendly increments, and recalculate on any booking, item, or policy change. The engine must be deterministic, fast (<150ms per calc), and idempotent, with graceful fallbacks when data is missing (e.g., default size class or average corridor distance). Expose results to the calendar, pricing/holds, and notifications via a consistent API.

Acceptance Criteria
Live Load Sensing & Forecasting
"As an organizer, I want the system to detect busy periods in my building so that buffer times expand automatically without manual coordination."
Description

Derive a real-time building load index from concurrent Sharehood bookings, time-of-day/week patterns, organizer-declared events (move-ins, maintenance), and optional calendar integrations. Smooth spikes with short-term averaging and provide a 24-hour forecast to inform buffer expansion/compression. Degrade gracefully when signals are sparse, and expose a normalized 0–100 load score consumable by the buffer engine and UI.

Acceptance Criteria
Adaptive Calendar Visualization
"As a neighbor booking an item, I want to clearly see when buffers apply on the calendar so that I can choose a time that won’t cause bottlenecks."
Description

Display buffer bands around pickup and return slots in the booking calendar and organizer dashboard with clear color-coding, legends, and tooltips indicating why buffers apply and their duration. Prevent selection within protected buffer periods while showing next available alternatives. Update visuals in real time when load or policy changes occur, and meet accessibility and mobile responsiveness standards.

Acceptance Criteria
Overlap Resolution & Auto-Reschedule
"As a borrower, I want the system to suggest the nearest conflict-free time when my preferred slot overlaps so that I don’t have to message back and forth."
Description

Automatically resolve doorway/elevator overlaps by expanding or compressing buffers within policy limits and proposing the nearest conflict-free times. Respect priority rules (earlier confirmed bookings anchor; new requests move) and avoid cascade thrashing with bounded adjustment attempts. Present alternatives for user confirmation, then lock times and propagate changes to all dependent bookings with a full audit trail.

Acceptance Criteria
Organizer Policy Controls & Overrides
"As an HOA admin, I want to set how aggressive buffers should be and override specific bookings so that the system matches my building’s rules."
Description

Provide building- and item-level settings for min/max buffer caps, load sensitivity, size-class mappings, weekend/peak rules, and elevator-outage modes. Allow one-off overrides per booking with role-based permissions. Persist policies versioned over time and surface the active policy context in UI and logs to explain buffer outcomes.

Acceptance Criteria
Deposit Hold Synchronization
"As an organizer, I want deposit holds to align with adjusted pickup and return windows so that no-shows are discouraged without overholding funds."
Description

Align Stripe deposit hold creation, capture window, and release with adjusted pickup/return times and their buffers. Initiate holds before the pickup buffer begins, extend holds automatically if returns shift later, and release on successful handoff confirmation or policy-defined timeout. Include idempotent retries and webhook handling to keep payment state consistent with schedule changes.

Acceptance Criteria
Change Notifications & Consent
"As a lender, I want to be notified and asked to confirm when buffers change my appointment times so that I’m never surprised at the door."
Description

Notify lenders and borrowers when buffers cause any schedule shift, summarizing the reason (load, policy, conflict), the delta, and required action. Require explicit consent for shifts beyond configurable thresholds; otherwise apply silent updates with heads-up alerts. Support push, email, and SMS, include deep links to accept/decline options, and log read receipts and responses.

Acceptance Criteria

Event Shield

Integrate building calendars (moves, deliveries, trash pickup, inspections) to auto‑apply temporary caps or blackout periods where needed. Affected bookings get smart reschedule suggestions that maintain deadlines. Organizers avoid last‑minute clashes; residents experience smoother, on‑time exchanges even on busy days.

Requirements

Building Calendar Integrations Gateway
"As an HOA/tenant organizer, I want to connect our building calendars to Sharehood so that caps and blackouts are applied automatically without manual data entry."
Description

Provide secure, configurable connectors to external building calendars, including Google Calendar, Microsoft 365/Outlook, iCal/ICS URLs, and property management systems (e.g., BuildingLink, AppFolio, Yardi). Support OAuth/API key authentication, one-time ICS upload, and ongoing sync via webhooks or scheduled polling. Normalize incoming events (moves, deliveries, trash pickup, inspections) into a unified schema with time zone handling, DST adjustments, deduplication, and conflict resolution. Expose per-building integration settings, permission scopes, and sync health indicators (last sync, errors, rate limits) to ensure reliable data ingestion and transparency.

Acceptance Criteria
Event-to-Restriction Rules Engine
"As an organizer, I want building events to automatically set appropriate caps or blackouts so that residents don’t book during resource conflicts."
Description

Implement a rules engine that translates imported building events into temporary blackouts or capacity caps. Allow configuration by event type, location/resource (elevator, loading dock, lobby), and time windows, including pre/post buffers and recurring patterns. Support multi-resource constraints, unit/floor exceptions, and rule priority/precedence with versioning and preview. Integrate with Sharehood’s availability computation so that rules dynamically affect search results, booking creation, and modification flows in real time.

Acceptance Criteria
Smart Reschedule Suggestions
"As a resident borrower, I want instant alternative time options when my booking is impacted so that I can keep my plans on time without manual searching."
Description

When a booking becomes affected by a new or updated restriction, calculate deadline-aware alternative slots that minimize disruption. Rank options by proximity to original time, user preferences, item owner availability, and building constraints; support split pickup/return windows if beneficial. Provide one-tap rebook with automatic updates to due times, reminders, and Stripe deposit holds, ensuring policy compliance and preserving audit history.

Acceptance Criteria
Affected Booking Detection & Notifications
"As an organizer, I want Sharehood to notify all impacted parties with actionable messages so that rescheduling happens quickly and transparently."
Description

Continuously evaluate synced events and rule changes to identify impacted bookings. Trigger timely, batched notifications via push, email, and SMS that explain the reason, show suggested alternatives, and indicate deadline impact. Offer actionable responses (accept, choose another time, request help), and notify organizers/owners of unresolved conflicts with escalation near deadlines. Maintain a complete audit trail of messages, decisions, and timestamps for accountability.

Acceptance Criteria
Capacity & Blackout Calendar UI
"As an organizer, I want a clear calendar visualization of constraints and capacity so that I can plan and explain availability to residents."
Description

Deliver a unified calendar interface overlaying external building events, derived blackouts, and per-slot capacity heatmaps. Provide filters by building, resource, and event type; tooltips revealing source event and rule; and conflict badges on bookings. Enable mobile-responsive views (day/week/agenda) and role-based visibility of event details. Support drag-to-propose adjustments and quick links to create exceptions (subject to permissions).

Acceptance Criteria
Admin Overrides & Exception Workflow
"As an organizer, I need a safe way to grant exceptions when justified so that urgent resident needs can be accommodated without undermining governance."
Description

Introduce a permissioned workflow for granting one-off exceptions during capped or blackout periods. Require reason codes and optional attachments, scope exceptions to specific users/items/locations/timeframes, and auto-expire them after use. Reflect overrides immediately in availability, update notifications accordingly, and log all actions for auditing and analytics to inform future rule tuning.

Acceptance Criteria

Window Harmonizer

Auto-aligns pickup and return windows across all items in your cart—even from different lenders and locations—so everything fits your event timeframe. Suggests small shifts to avoid conflicts, respects building quiet hours, and highlights the most efficient plan in one view. Fewer trips, no overlaps, on‑time starts.

Requirements

Cross-Lender Window Optimization Engine
"As a borrower, I want all my pickups and returns aligned to my event timeframe so that I can collect everything in fewer trips without time conflicts."
Description

Compute aligned pickup and return windows across all items in a cart spanning multiple lenders and locations within a user-defined event timeframe. The engine ingests item availability, lender preferences, location constraints, user buffers, and time zone to generate a feasible, non-overlapping schedule. It merges compatible windows to reduce trips, honors minimum/maximum loan durations, and outputs a plan with per-item windows and a consolidated itinerary. Integrates with Sharehood’s item calendars and booking APIs as a pre-checkout step and can lock provisional holds on selected windows until checkout completion.

Acceptance Criteria
Quiet Hours & Policy Compliance
"As an HOA organizer, I want the schedule to respect our building’s quiet hours so that pickups and returns don’t disturb residents or break policies."
Description

Automatically enforce building quiet hours, HOA rules, and lender-specific access constraints during window optimization. The system sources policies from property profiles tied to addresses and lender settings, applies them as hard constraints, and blocks or adjusts windows that would violate rules. Supports exceptions (holidays, loading zones), per-building grace periods, and user-visible rationale for any blocked time. Provides override gates where permitted and logs compliance decisions for auditing.

Acceptance Criteria
Route-Aware Pickup Sequencing
"As a borrower, I want the app to suggest the most efficient pickup order so that I spend less time traveling and start my event on time."
Description

Optimize the order of pickups and returns using real-time and historical travel data to minimize total travel time and backtracking. Incorporates transport mode (walk, bike, car), parking/elevator buffers, lender lead times, and user-defined location preferences. Produces a sequenced itinerary with target arrival windows and route guidance hooks. Re-optimizes when items are added/removed or suggestions are applied, and exposes routing metadata to the UI for transparency.

Acceptance Criteria
Micro-Shift Suggestions & One-Tap Apply
"As a borrower, I want smart suggestions for slight time adjustments so that I can avoid overlaps without manually tinkering with every item."
Description

Propose small, data-driven time shifts (e.g., ±5–30 minutes) to pickup/return windows that resolve conflicts or reduce travel time while staying within lender availability and policy constraints. Each suggestion includes a reason (conflict avoidance, quiet hours, congestion) and shows before/after impacts. Users can accept a single suggestion or apply all with one tap; the system then recalculates and updates provisional holds as needed. Respects user flexibility settings and requests lender confirmation if a shift exceeds default tolerances.

Acceptance Criteria
Live Conflict Detection & Auto-Recalculation
"As a borrower, I want the plan to update immediately when availability changes so that I don’t unknowingly check out with conflicting times."
Description

Continuously monitor cart contents, lender calendar updates, and policy changes to detect conflicts in near real time. When a conflict arises, trigger an automatic recomputation of windows and present the best alternative plan, preserving previously accepted constraints when possible. Utilize optimistic locking to prevent double-booking, and push updates over WebSocket to all user sessions. Target recomputation under 500 ms for up to 10 items and three locations, with graceful degradation and clear user prompts when manual action is required.

Acceptance Criteria
Unified Plan View & Calendar Export
"As a borrower, I want a clear, shareable view of my optimized schedule so that I can follow it easily and coordinate with others."
Description

Provide a single, interactive view that highlights the most efficient plan, combining timeline and map visualization of pickups, returns, travel segments, buffers, and constraints. Color-code compliant vs. at-risk windows, surface rationale tooltips, and allow quick edits (drag to adjust within allowed bounds). Support exporting the final plan to Google/Apple Calendar, generating a shareable link for co-planners, and printing a concise itinerary. Ensure accessibility and mobile-first responsiveness.

Acceptance Criteria

Hold Split

Runs one checkout with itemized deposit holds per lender, keeping funds and approvals separate under a single receipt. If one item changes or is declined, the rest of your booking stands. Holds release independently at each verified return, improving liquidity and reducing headaches.

Requirements

Multi‑Lender Checkout Orchestration
"As a borrower, I want to check out once for items from multiple neighbors so that I don’t have to run separate payments and I keep my confirmed items even if one lender declines."
Description

Implements a single checkout flow that aggregates items from multiple lenders while creating separate deposit hold authorizations per lender. The orchestrator splits the cart by lender, computes per‑lender deposit amounts and policies, and submits independent Stripe authorizations with idempotency keys. Booking creation is atomic for successfully authorized items and resilient to partial failures: if one lender declines or an authorization fails, unaffected items remain confirmed with their pickup windows reserved. The flow ensures calendar availability is only blocked for items that successfully authorize, and it maintains a unified session and anti‑duplication protection across retries. Integrates with Sharehood’s smart pickup windows to reflect only confirmed items and aligns with organizer dashboards for oversight.

Acceptance Criteria
Per‑Lender Itemized Deposit Authorization
"As a lender, I want my deposit hold to be calculated and authorized separately from other lenders so that my risk and policy are applied independently."
Description

Calculates and authorizes deposit holds per lender based on item risk profiles, lender policy, and booking duration. Supports configurable deposit rules (flat, tiered by item category, percentage of replacement value), minimum/maximum caps, and tax/fee exclusions. Each lender receives an independent authorization request, enabling separate approval flows and compliance with lender preferences. Handles currency rounding, partial cart changes, and re‑pricing prior to pickup by requesting incremental authorizations as needed without impacting other lenders’ holds. Stores policy snapshots on booking to ensure consistent adjudication at return time.

Acceptance Criteria
Independent Hold Release on Verified Return
"As a borrower, I want my deposit for a returned item released right away even if other items are still out so that my funds aren’t tied up unnecessarily."
Description

Releases each lender’s deposit hold immediately upon their item’s verified return, independent of other items in the booking. Integrates with check‑in signals (QR scan, organizer verification, photo evidence) and handles partial returns, late fees, and damage escalations. If a capture is required (damages/no‑show), performs a compliant partial capture within authorization windows or issues a separate charge if the hold has expired. Prevents duplicate releases, records audit trails, and updates borrower liquidity in real time while keeping the rest of the booking unaffected.

Acceptance Criteria
Partial Approval & Failure Resilience
"As a borrower, I want unaffected items in my booking to remain confirmed if one item is declined or changed so that I don’t lose my whole reservation."
Description

Ensures the booking survives item‑level declines, policy changes, or availability conflicts without canceling unrelated items. On decline or change, the system re‑quotes only the affected items, proposes alternatives, or allows removal while preserving confirmed items and pickup windows. Provides clear borrower prompts, time‑boxed decision windows, and automatic reflow of calendar holds. Maintains consistent state across services via idempotent operations and compensating actions, with full event logs for support resolution.

Acceptance Criteria
Unified Receipt & Split Ledgering
"As a finance operator, I want one receipt for the borrower and split ledger entries per lender so that reconciliation and support are accurate and efficient."
Description

Generates a single borrower receipt that itemizes rental fees and per‑lender deposit holds with real‑time statuses (authorized, adjusted, released, captured). Provides lenders and organizers with a split view showing only their items, amounts, and events. Mirrors financial events into Sharehood’s internal ledger with per‑lender sub‑ledgers, reconciliation references (Stripe PaymentIntent/Authorization IDs), and daily summaries for ops. Supports refunds/adjustments, tax reporting separation, and export to accounting systems.

Acceptance Criteria
Hold Refresh & Escalation for Extended Rentals
"As a borrower, I want the system to manage deposit holds for long rentals so that my booking isn’t canceled just because a hold expired."
Description

Monitors authorization lifetimes and automatically refreshes or sequences holds for bookings that exceed card hold windows. Before expiry, attempts incremental re‑authorization or rolling holds per lender; if refresh fails, notifies borrower to update payment and alerts the lender with clear next steps. Applies configurable grace periods, fallback to separate charges where allowed, and preserves unaffected lenders’ holds. All actions are tracked for compliance and dispute defense.

Acceptance Criteria
Lifecycle Notifications & Webhook Reliability
"As a lender, I want timely, reliable alerts about my item’s deposit hold status so that I can manage handoffs and returns with confidence."
Description

Delivers real‑time, per‑lender notifications for key hold events (authorized, failed, adjusted, released, captured) and a consolidated borrower timeline in app and email. Implements resilient processing of Stripe webhooks with retries, signature verification, idempotency, and dead‑letter handling to keep state consistent even under outages. Surfaces clear UI states and audit trails so support can diagnose discrepancies quickly without impacting other items in the booking.

Acceptance Criteria

Slot Freeze

Temporarily reserves your selected time slots across all items while you finalize checkout, preventing last‑second sniping and calendar drift. A visible countdown keeps you informed, with fair extensions when you’re verifying identity or adding co‑organizers. More certainty, less scramble.

Requirements

Atomic Multi-Item Slot Hold
"As a borrower coordinating multiple items, I want all my selected time slots to be temporarily held together so that I can complete checkout without losing availability on any item."
Description

When a borrower selects time ranges across multiple items, the system creates an atomic, time-boxed hold on all selected item/slot pairs. Holds are all-or-nothing: if any slot cannot be held, none are. The hold duration is configurable with a server-enforced TTL. Holds block other users from booking those exact slots, and other users see them as “temporarily held.” Implementation uses per-item, per-time-range distributed locks with idempotency keys, conflict checks against existing bookings/holds, and automatic release on completion, explicit cancel, or timeout. Integrates with Sharehood’s inventory calendar and smart pickup windows to ensure consistency and prevent oversubscription.

Acceptance Criteria
Countdown Timer & State Sync
"As a borrower, I want a clear countdown that follows me during checkout and reflects any extensions so that I know exactly how much time I have to finish."
Description

Provide a persistent, real-time countdown banner that shows remaining hold time across all checkout steps and devices. The UI syncs with the server every few seconds or via websockets to reflect extensions, expirations, or cancellations. It displays reasons for extensions (e.g., identity check) and warns at configurable thresholds. The component is responsive, accessible (ARIA live regions, screen reader friendly), localized, and resilient to tab switches. Multiple tabs/devices share the same session state to avoid double countdowns and conflicting actions.

Acceptance Criteria
Fair-Use & Anti-Abuse Controls
"As an organizer, I want safeguards against repeated slot freezes without intent to book so that my calendar remains fair and available to genuine borrowers."
Description

Enforce policies that prevent freeze abuse: limit concurrent holds per account/device/IP, cap daily freeze attempts, and apply cooldowns after repeated expirations without booking. Detect patterns like rapid cycling, multi-account abuse, or scripted holds and automatically throttle or block. Provide organizers with configurable thresholds and admin overrides. All policy decisions are logged with reasons for auditability, and error states are communicated to users with clear guidance.

Acceptance Criteria
Conflict Handling & Drift Prevention
"As a borrower, I want the calendar to stay accurate while I’m checking out so that I don’t encounter surprises at confirmation."
Description

Ensure deterministic outcomes when multiple users target overlapping slots. On simultaneous requests, apply first-valid-lock wins with monotonic timestamps and return actionable alternatives to late contenders. Reconcile holds with Sharehood’s smart pickup window logic to auto-adjust buffers and prevent drift. On hold release or expiry, immediately recalculate availability and broadcast updates to waiting users. Guarantee calendar consistency via transactional writes and rollback on partial failures.

Acceptance Criteria
Extension Triggers & Policy Engine
"As a borrower completing required verification, I want my hold extended fairly so that I don’t lose my slot due to necessary checks."
Description

Define server-side rules that grant fair, limited extensions for specific, verifiable steps: identity verification, payment authentication (e.g., 3DS), adding co-organizers, or address confirmation. Extensions are configurable (per trigger, per tenant), capped by a maximum cumulative extension per session, and recorded for auditing. The engine publishes state changes to the UI, updates countdowns in real time, and denies extensions that exceed policy limits with clear messaging and next steps.

Acceptance Criteria
Resilience & Recovery
"As a borrower who briefly lost connection, I want my frozen slots to persist so that I can resume checkout without starting over."
Description

Persist hold state server-side so users can recover from app crashes, network loss, or device switches within the freeze window. On reconnection, restore the active hold, countdown, and checkout progress. Implement graceful degradation to polling if realtime channels fail, and send optional push/email warnings before expiration. Ensure all locks are released on timeout or unrecoverable errors to avoid stranded holds.

Acceptance Criteria
Observability & Reporting
"As a product manager, I want visibility into Slot Freeze performance so that we can tune durations and policies to maximize conversions and fairness."
Description

Capture and visualize key metrics: holds created, average hold duration, extensions by trigger, expiry reasons, conversion rate to booking, abuse rate, and organizer-level impacts. Provide dashboards, anomaly alerts (e.g., spike in expirations), and export to analytics/BI. Include trace and log correlation for debugging race conditions or lock contention, with PII-safe practices and retention policies.

Acceptance Criteria

Trust Match

Pre‑flight checks your eligibility across every item in the cart—trust tier, vouches, and deposit requirements—then flags any gaps before you pay. See clear steps to qualify or swap to accessible alternatives, ensuring instant approvals and smoother multi‑owner bookings.

Requirements

Unified Eligibility Engine
"As a borrower, I want the system to check my eligibility for all items at once so that I know I’ll be approved before I pay."
Description

A rules-driven service that evaluates user eligibility for each item in the cart against trust tier, vouch count, identity verification status, payment method deposit capability, prior infractions, and owner-specific policies (minimum tier, max concurrent loans, restricted users). Supports batch evaluation of all cart items and returns structured outcomes (pass, soft-block, hard-block) with standardized reason codes and severities. Exposes a synchronous API for checkout and cart updates with <300 ms p95 latency for carts up to 10 items. Includes idempotency, rate limiting, and fallback defaults when upstream services degrade. Integrates with trust-tier service, vouch graph, identity provider, and payments profile. Emits analytics events and stores ephemeral decision context for immediate UI rendering.

Acceptance Criteria
Multi-Item Preflight Checkout Gate
"As a borrower, I want a preflight that flags any blockers before I pay so that I can fix issues without failed bookings."
Description

A pre-payment checkpoint that automatically runs eligibility for every cart item and cross-item constraints (overlapping pickup/return windows, max concurrent bookings) on any cart change and on Pay click. Consolidates results into a single pass/fail banner with per-item chips and inline actions. Blocks payment on any hard failure; allows proceed with warnings for soft issues. Re-evaluates in real time after user fixes and displays ETA for long-running checks (e.g., ID verification). Provides resilient UX states for slow networks and degraded dependencies. Telemetry includes pass rate, top failure codes, and time-to-resolution.

Acceptance Criteria
Gap Resolution & Guided Actions
"As a borrower, I want clear steps to qualify or alternatives so that I can complete my booking successfully."
Description

Actionable guidance to resolve ineligibility: prompts to complete ID verification, request or add vouches, link a deposit-capable card, adjust dates to remove conflicts, reduce quantity, or remove blocked items. Includes deep-linked CTAs, progressive disclosure, and instant re-check after each action. Persists partial progress and surfaces eligibility countdowns (e.g., vouch pending). Provides contextual education (why it’s required, who sees what) and respects accessibility standards. Tracks conversion from blocker to success for optimization.

Acceptance Criteria
Accessible Alternatives & Smart Swaps
"As a borrower, I want similar items I can book right now if one is blocked so that I don’t waste time."
Description

Recommendation engine that suggests bookable alternatives when an item fails eligibility or availability. Matches by category, key specs, distance, owner rating, price, and calendar fit within the desired window. Filters to options the user already qualifies for given their trust tier and deposit limit. Enables one-tap swap that preserves cart structure and re-runs preflight. Displays clear differences (specs, price delta, pickup window). Supports fallback suggestions across nearby time slots if no exact match exists.

Acceptance Criteria
Deposit Hold & Owner Policy Aggregation
"As a borrower, I want to know my total deposit holds and whether my card can cover them so that I can choose how to proceed before paying."
Description

Computes per-owner deposit requirements, aggregates totals, and verifies the user’s payment method can support required pre-authorizations across multi-owner carts. Integrates with Stripe to place separate or combined holds per owner while ensuring atomicity—no booking is created unless all holds succeed. Handles partial failures, retries, and expiration windows; displays per-owner breakdown and total hold amount pre-payment. Supports secondary payment methods for holds, release on cancel, and automatic adjustment when items are swapped.

Acceptance Criteria
Decision Explainability & Audit Trail
"As a support agent, I want a trace of how Trust Match decided eligibility so that I can resolve disputes quickly."
Description

Generates human-readable explanations and machine-readable traces for every eligibility decision, including evaluated inputs, rule versions, and outcomes. Stores signed, tamper-evident logs for 180 days with PII minimization and access controls for support and owners per policy. Exposes reason codes to the UI and a support console for deep dives. Includes consent tracking, export for disputes, and metrics to monitor false declines and rule drift. Enables rapid tuning via feature flags and A/B tests without losing audit continuity.

Acceptance Criteria

Hub Handoff

Consolidates multi‑owner pickups to a single, nearby handoff point—like an HOA gear closet, lobby shelf, or smart locker—on a shared window. Each item uses its own secure access code, creating one quick stop with tamper‑resistant receipts. Ideal for block parties and team events.

Requirements

Unified Hub Window Scheduling
"As a borrower planning a team event, I want all my items ready at one nearby hub window so that I can make a single stop and stay on schedule."
Description

Implements a scheduling engine that consolidates multiple item pickups and returns from different owners into a single, shared time window at a designated hub (e.g., HOA closet, lobby shelf, smart locker). The engine aligns with Sharehood’s live calendar, auto-adjusts for overlaps, applies buffer times for staging, respects hub operating hours and capacity, and re-optimizes when bookings change. It supports single-stop itineraries for borrowers, generates owner drop-off deadlines ahead of the shared window, and provides conflict resolution and fallback to doorstep exchange if hub constraints cannot be met. Output includes confirmed hub window, item grouping, and notifications for all parties.

Acceptance Criteria
Per-Item Secure Access Codes
"As a borrower, I want a secure code for each item so that I can access only what I reserved without risking others’ gear."
Description

Generates unique, time-bound, single-use access credentials for each booked item at the hub. Supports QR and PIN formats with configurable validity windows for drop-off and pickup, auto-rotating codes for extended windows, and revocation on booking changes. Integrates with different hub types: printed QR seals for open shelves, PIN/QR for smart lockers, and keypad codes for controlled closets. Stores minimal secrets, hashes for audit, and includes offline fallback tokens to ensure access continuity during connectivity issues.

Acceptance Criteria
Tamper-Resistant Digital Receipt
"As an owner, I want a tamper-resistant receipt of each exchange so that deposits and disputes can be resolved fairly and quickly."
Description

Creates a chain-of-custody receipt for each item that records owner drop-off, hub intake, borrower pickup, and return events with timestamps, user IDs, access code hashes, and optional condition photos. The receipt is locked after each stage, includes geotag (where permissible), and is immutable to support deposit disputes. It integrates with notifications, Sharehood’s booking record, and Stripe deposit logic to auto-release or flag holds based on the recorded state and any reported issues.

Acceptance Criteria
Hub Capacity and Eligibility Rules
"As an HOA organizer, I want to set who can use the hub and when so that the space stays orderly and compliant with our building policies."
Description

Provides configurable rules per hub: daily/slot capacity, operating hours, allowed item categories and sizes, member eligibility (e.g., HOA residents), and verification requirements. The scheduler enforces these constraints when consolidating stops, surfaces conflicts to users, and offers alternatives (different window, different hub, or doorstep). Admins can override with audit logging. Supports blackout periods and maintenance windows for smart lockers.

Acceptance Criteria
Consolidated Itinerary and Guidance
"As a borrower, I want clear instructions and a single itinerary so that I can pick up multiple items quickly without confusion."
Description

Delivers end-to-end guidance for owners and borrowers: pre-drop checklists, packing labels with slot/shelf assignments, hub map and access instructions, and a single consolidated itinerary for borrowers covering all items in the hub window. Sends smart reminders (email, push, SMS) for owner drop-off deadlines and borrower pickup windows, and provides ADA-friendly directions and multilingual templates. Includes failure guidance (e.g., hub full, code not working) with one-tap support escalation.

Acceptance Criteria
Stripe Deposit Coordination for Hub Exchanges
"As an owner, I want deposits managed automatically across all my items in a hub exchange so that I’m protected without manual tracking."
Description

Aligns Stripe deposit holds with hub-based, multi-item bookings. Supports per-item holds aggregated into one authorization, partial releases as items are returned, and automatic adjustments driven by the digital receipt state machine. Handles no-shows, late returns, and damage claims with configurable fees, retries, and notifications. Ensures idempotent webhook processing and clear settlement reporting for organizers and owners.

Acceptance Criteria
Smart Locker and Access Device Integration
"As an organizer, I want reliable locker integrations so that hub handoffs work seamlessly even with different hardware vendors."
Description

Provides an integration layer for common smart lockers and access devices (e.g., API/webhook connectors, device simulators, and a vendor-agnostic abstraction). Maps per-item access codes to locker compartments, supports remote open/close events, and reconciles device logs with Sharehood’s receipts. Includes health checks, retries, rate limiting, and a manual fallback flow that converts locker failures into supervised shelf handoffs with new codes and audit notes.

Acceptance Criteria

Split Pay

Share costs and deposits with teammates in one flow. Split by item or percentage, send invites for one‑tap authorization, and get separate receipts while keeping a unified booking. Budgets stay fair, and no one front‑loads the entire deposit burden.

Requirements

Split Configuration & Calculation Engine
"As a borrower organizing a group booking, I want to configure how rental costs and deposit are split among teammates so that everyone pays a fair share without manual math."
Description

Provide a configuration module that lets an initiator define how rental costs, fees, taxes, and deposit holds are shared among participants. Support equal split, percentage-based split, fixed-amount contributions, and item-level splitting (per item or per booking total). Include per-member max contribution caps, rounding rules that preserve totals, currency precision, and validation that allocations sum to 100% or the total amount. Handle mixed tax rates and service fees by distributing proportionally or per configured rule. Expose a clear UI summary and an API contract that outputs each participant’s cost, deposit hold amount, and payment intent metadata for downstream processing.

Acceptance Criteria
One‑Tap Authorization Invites
"As an invited teammate, I want to authorize my portion with one tap from a secure invite so that I can join the booking quickly using my saved payment method."
Description

Enable initiators to invite teammates to authorize their share via secure deep links delivered by push, email, or SMS. Links open a pre-filled checkout with the participant’s allocation and deposit hold, supporting one-tap confirm using Stripe Link/Apple Pay/Google Pay where available. Include invite expiration, automatic reminders, status tracking (pending, authorized, declined, expired), and the ability to resend or revoke invites. Ensure device and session security (signed tokens, short-lived links), and require minimal steps for known users while allowing guided sign-in for new users.

Acceptance Criteria
Unified Booking Hold with Pending Shares
"As a booking initiator, I want the items reserved while my team authorizes payment so that availability doesn’t disappear mid-checkout."
Description

Place a provisional hold on selected items and time slots while participant authorizations complete. Integrate with the live calendar and smart pickup windows to prevent double-booking during the invite window. Support configurable hold duration, progress thresholds (e.g., booking locks when ≥N of M shares authorized), and outcomes: auto-cancel and release inventory on timeout, or allow the initiator to cover remaining shares or reassign them. Persist partial authorizations and audit trail to ensure consistency after retries or rebalancing.

Acceptance Criteria
Stripe Multi‑Party Payments & Deposit Holds
"As a payer, I want my card authorized only for my share of costs and deposits so that I’m never liable for the entire booking amount."
Description

Implement Stripe workflows that create per-participant PaymentIntents for their cost share and associated deposit hold, all linked to a single Sharehood Booking ID. Support SCA/3DS, idempotency, and webhook-driven state updates. Ensure deposit holds are authorized per user, captured or released based on booking outcomes (completion, no-show, damage), and never require one user to front-load another’s deposit unless explicitly configured. Handle partial refunds, proportional deposit releases, and dispute notifications per participant. Maintain PCI compliance boundaries and robust error recovery.

Acceptance Criteria
Per‑Participant Receipts & Unified Ledger
"As a team, we want individual receipts and a shared booking record so that our accounting and reimbursements are clear and traceable."
Description

Generate individual receipts/invoices for each participant covering their cost, taxes, fees, and deposit authorization, while maintaining a unified booking ledger for the organizer and item owner. Provide downloadable/email receipts, a consolidated booking summary, and clear mapping between participants, items, and amounts. On cancellations, changes, or damage assessments, distribute refunds or additional charges proportionally or per configured responsibility rules, and log all adjustments with timestamps for HOA/tenant reporting and audits.

Acceptance Criteria
Failure Handling, Reassignment & Notifications
"As an organizer, I want clear alerts and the ability to reassign or cover failed shares so that the booking can still proceed on time."
Description

Deliver a resilient flow for declines, timeouts, and insufficient funds. Notify the initiator and affected participants with actionable messages, and offer options to reassign a share to another teammate, rebalance remaining allocations per the chosen split rules, or allow the initiator to cover the remainder. Define cutoffs before pickup, update booking holds accordingly, and surface clear error states in the UI. Provide observability (events, logs, metrics), localization for messages, and accessibility-compliant notifications across push, email, and SMS.

Acceptance Criteria

Pickup Delegation

Assign specific items to different people for pickup and return, with precise windows, access codes, and proof steps. Delegates see only their tasks; organizers track status in one timeline. Workload spreads out, handoffs stay accountable, and events start on time.

Requirements

Multi-Delegate Item Assignment
"As an organizer, I want to assign each item to specific delegates for pickup and return so that workload is distributed and accountability is clear."
Description

Enable organizers to assign pickup and return responsibilities per item to different delegates within a single booking or event. Support specifying delegate roles (pickup vs. return), task notes, and location for each handoff. The assignment UI should allow bulk selection and splitting of item lists across multiple people, while preserving a single booking context. All assignments must map to existing Sharehood bookings and inventory, respecting item availability and preventing double-assignment. The outcome is clear ownership of each handoff step, distributing workload and making accountability explicit.

Acceptance Criteria
Per-Delegate Time Windows with Auto-Adjust
"As an organizer, I want the system to generate precise pickup and return windows that auto-adjust to overlaps so that delegates aren’t double-booked and events start on time."
Description

Provide precise pickup/return windows per delegate that auto-adjust for conflicts, travel buffers, and location hours. Integrate with Sharehood’s live calendar so that delegate windows do not overlap with each other or existing commitments for the same items. Include configurable buffers (e.g., 10–30 minutes) and automatic reflow when organizer updates item lists or delegates change. Surface warnings for infeasible schedules and propose the nearest available alternatives. Result: fewer late starts and no double-bookings.

Acceptance Criteria
Secure Access Codes and Instructions Distribution
"As an organizer, I want to provide per-delegate access codes and instructions so that each delegate can retrieve or return items securely and without confusion."
Description

Allow organizers to attach per-delegate access credentials (e.g., lockbox codes, door codes) and step-by-step pickup/return instructions to each task. Securely store and distribute codes via time-bound links and mask codes until within the valid window. Include audit logging for code views and automatic code rotation reminders when tasks are rescheduled. Support attachments (maps, photos of lockbox) and quick replies for delegates to confirm understanding. Integrates with Sharehood notifications (email/SMS/push).

Acceptance Criteria
Handoff Proof Workflow (Photos, Scan, Checklist)
"As an organizer, I want required proof steps at pickup and return so that item handoffs are auditable and disputes are minimized."
Description

Require configurable proof steps at pickup and return (e.g., photo of item, QR/barcode scan, condition checklist, PIN/signature). Support offline capture with later sync, and verify item identity via QR codes already associated with inventory. Store proofs on the booking timeline with timestamps, location (when permitted), and delegate identity. Block task completion and code reveal for return until required steps are fulfilled. This creates an auditable chain of custody and reduces disputes.

Acceptance Criteria
Delegate-Only Task View and Permissions
"As a delegate, I want a simple view of only my assigned tasks so that I can complete pickups/returns quickly without seeing unrelated information."
Description

Provide delegates a minimal, secure view showing only their assigned tasks, windows, locations, and proofs to complete—no access to other items, pricing, or personal data. Support passwordless login via magic link or OTP, with session limits and device checks. Respect privacy by redacting unrelated borrower/neighbor details while still enabling necessary contact or chat via a proxied channel. Ensures compliance with Sharehood’s data policies and reduces cognitive load for occasional helpers.

Acceptance Criteria
Organizer Timeline, Tracking, and Alerts
"As an organizer, I want a consolidated timeline and alerts for each delegate’s progress so that I can intervene early and keep the schedule on track."
Description

Aggregate all delegated tasks into a single timeline per booking/event, showing real-time status (scheduled, en route, picked up, returned, failed) with proof artifacts inline. Provide proactive alerts for risks (late start, missing proof, window breach) and one-click actions (nudge delegate, extend window, reassign task). Integrate with Sharehood’s notification stack and calendar, keeping the organizer informed without manual check-ins. Outcome: early intervention and on-time starts.

Acceptance Criteria
Per-Task Deposit Hold Coordination
"As an organizer, I want deposit holds linked to each delegated pickup so that no-shows are deterred and refunds can be handled per item."
Description

Tie Stripe deposit holds to delegated pickup tasks at the item level. Place or adjust holds when a delegate is assigned or reassigned, and release or capture holds based on proof outcomes (e.g., item returned in good condition). Support partial holds for multi-item bookings, handle partial cancellations, and reconcile fees automatically. Reflect financial status on the organizer timeline to make monetary accountability visible alongside task status.

Acceptance Criteria

Product Ideas

Innovative concepts that could enhance this product's value proposition.

Trust Rings

Layered trust via ID check and neighbor vouches; pickup selfie with geotag confirms handoffs. Converts skeptics and boosts lender confidence.

Idea

No-Show Shield

Dynamic deposit holds based on history; auto-relist if pickup window lapses and instant waitlist offers. Cuts idle time and deters flakes.

Idea

Project Chain

Plan multi-step projects by reserving sequential items in one flow; auto-suggests alternates and compresses windows to finish by your deadline.

Idea

Silent Swap

Code-verified, contactless handoffs using temporary PINs and quiet-hour-aware windows. Perfect for late-night pickups without doorbells or chatter.

Idea

Demand Pulse

Realtime demand pings alert dormant listers when neighbors search their items; one-tap relist with auto-refreshed calendar restores circulation.

Idea

Hallway Flow

HOA scheduling that staggers building pickups, shows heatmaps, and caps simultaneous handoffs per floor. Cuts congestion and complaints.

Idea

Unified Cart

Checkout once for multi-owner bookings; splits deposits per lender and syncs pickup windows across locations. Simplifies block-party planning.

Idea

Press Coverage

Imagined press coverage for this groundbreaking product concept.

Want More Amazing Product Ideas?

Subscribe to receive a fresh, AI-generated product idea in your inbox every day. It's completely free, and you might just discover your next big thing!

Product team collaborating

Transform ideas into products

Full.CX effortlessly brings product visions to life.

This product was entirely generated using our AI and advanced algorithms. When you upgrade, you'll gain access to detailed product requirements, user personas, and feature specifications just like what you see below.