fix: make property-assessor safer for whatsapp runs
This commit is contained in:
180
docs/plans/2026-03-28-property-assessor-whatsapp-safe-runtime.md
Normal file
180
docs/plans/2026-03-28-property-assessor-whatsapp-safe-runtime.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Property Assessor WhatsApp-Safe Runtime Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Keep WhatsApp property-assessor runs moving by failing fast on silent discovery/photo hangs, avoiding helper subprocesses during core analysis, and reserving subprocess use to the final PDF render attempt only.
|
||||
|
||||
**Architecture:** Add small timeout guards around the existing in-process listing discovery and photo extraction calls so one quiet browser-backed task cannot stall the entire assessment. Tighten the live skill and published docs so messaging runs treat chat-native source collection as the default path and helper commands as non-chat or final-render-only tools.
|
||||
|
||||
**Tech Stack:** TypeScript, Node test runner, existing OpenClaw property-assessor skill, existing OpenClaw web-automation modules, Markdown docs.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add failing timeout tests for discovery and photo extraction
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/property-assessor/tests/assessment.test.ts`
|
||||
|
||||
**Step 1: Write the failing test**
|
||||
|
||||
Add tests that stub discovery/photo functions with never-resolving promises and assert that:
|
||||
- listing discovery returns `null` URLs and records timeout attempts
|
||||
- photo extraction returns `not completed` instead of hanging forever
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `npm test -- --test-name-pattern "times out"`
|
||||
Expected: FAIL because current code never times out or records timeout attempts.
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
Implement the smallest timeout wrapper needed for the tests to pass.
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `npm test -- --test-name-pattern "times out"`
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/property-assessor/tests/assessment.test.ts
|
||||
git commit -m "test: cover stalled discovery and photo extraction"
|
||||
```
|
||||
|
||||
### Task 2: Implement hard timeout guards in the live assessment path
|
||||
|
||||
**Files:**
|
||||
- Create: `skills/property-assessor/src/async-timeout.ts`
|
||||
- Modify: `skills/property-assessor/src/listing-discovery.ts`
|
||||
- Modify: `skills/property-assessor/src/photo-review.ts`
|
||||
|
||||
**Step 1: Write the failing test**
|
||||
|
||||
Use the tests from Task 1 as the red phase.
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `npm test -- --test-name-pattern "times out"`
|
||||
Expected: FAIL
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
Add:
|
||||
- a shared timeout helper for async operations
|
||||
- timeout-wrapped Zillow/HAR discovery in `listing-discovery.ts`
|
||||
- timeout-wrapped Zillow/HAR photo extraction in `photo-review.ts`
|
||||
- clear timeout attempt messages so the assessment can continue honestly
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `npm test -- --test-name-pattern "times out"`
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/property-assessor/src/async-timeout.ts skills/property-assessor/src/listing-discovery.ts skills/property-assessor/src/photo-review.ts skills/property-assessor/tests/assessment.test.ts
|
||||
git commit -m "fix: fail fast on stalled property-assessor extraction steps"
|
||||
```
|
||||
|
||||
### Task 3: Tighten live skill instructions for WhatsApp-safe execution
|
||||
|
||||
**Files:**
|
||||
- Modify: `../skills/property-assessor/SKILL.md`
|
||||
|
||||
**Step 1: Write the failing test**
|
||||
|
||||
No automated test. Use the documented runtime rule as the spec:
|
||||
- WhatsApp/messaging runs must avoid helper subprocesses for core analysis
|
||||
- only the final PDF render attempt may use the helper subprocess path
|
||||
- `update?` must remain status-only
|
||||
|
||||
**Step 2: Run verification to confirm current docs are wrong**
|
||||
|
||||
Run: `rg -n "scripts/property-assessor assess|node zillow-photos|node har-photos|Good:" ../skills/property-assessor/SKILL.md`
|
||||
Expected: current doc still presents helper commands as normal chat-safe core workflow.
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
Update the live skill doc to:
|
||||
- prefer `web_search`, `web_fetch`, and bounded `web-automation` for core assessment
|
||||
- forbid `scripts/property-assessor assess`, `node zillow-photos.js`, `node har-photos.js`, and ad hoc `curl` as the default WhatsApp core path
|
||||
- allow a single final PDF render attempt only after a decision-grade verdict exists
|
||||
|
||||
**Step 4: Run verification**
|
||||
|
||||
Run: `sed -n '1,220p' ../skills/property-assessor/SKILL.md`
|
||||
Expected: the WhatsApp-safe runtime rules are explicit and unambiguous.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add ../skills/property-assessor/SKILL.md
|
||||
git commit -m "docs: clarify whatsapp-safe property-assessor execution"
|
||||
```
|
||||
|
||||
### Task 4: Mirror the runtime guidance into the published repo docs
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/property-assessor.md`
|
||||
- Modify: `docs/web-automation.md`
|
||||
|
||||
**Step 1: Write the failing test**
|
||||
|
||||
No automated test. The spec is consistency with the live skill instructions.
|
||||
|
||||
**Step 2: Run verification to confirm current docs drift**
|
||||
|
||||
Run: `rg -n "node zillow-photos|node har-photos|assess --address" docs/property-assessor.md docs/web-automation.md`
|
||||
Expected: current docs still imply subprocess-heavy commands are the standard chat path.
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
Document:
|
||||
- chat-native assessment first
|
||||
- timeout-protected discovery/photo extraction behavior
|
||||
- final-render-only subprocess attempt from messaging runs
|
||||
|
||||
**Step 4: Run verification**
|
||||
|
||||
Run: `sed -n '1,220p' docs/property-assessor.md && sed -n '1,220p' docs/web-automation.md`
|
||||
Expected: published docs match the live skill behavior.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/property-assessor.md docs/web-automation.md
|
||||
git commit -m "docs: document whatsapp-safe property assessment flow"
|
||||
```
|
||||
|
||||
### Task 5: Verify the focused runtime behavior
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/property-assessor/tests/assessment.test.ts`
|
||||
- Verify: `skills/property-assessor/src/*.ts`
|
||||
- Verify: `../skills/property-assessor/SKILL.md`
|
||||
- Verify: `docs/property-assessor.md`
|
||||
- Verify: `docs/web-automation.md`
|
||||
|
||||
**Step 1: Run focused tests**
|
||||
|
||||
Run: `npm test`
|
||||
Expected: all `property-assessor` tests pass, including timeout coverage.
|
||||
|
||||
**Step 2: Run targeted source verification**
|
||||
|
||||
Run: `rg -n "withTimeout|timed out|final PDF render" skills/property-assessor/src ../skills/property-assessor/SKILL.md docs/property-assessor.md docs/web-automation.md`
|
||||
Expected: timeout guards and the final-render-only messaging rule are present.
|
||||
|
||||
**Step 3: Inspect git status**
|
||||
|
||||
Run: `git status --short`
|
||||
Expected: only intended files are modified.
|
||||
|
||||
**Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/property-assessor/src/async-timeout.ts skills/property-assessor/src/listing-discovery.ts skills/property-assessor/src/photo-review.ts skills/property-assessor/tests/assessment.test.ts ../skills/property-assessor/SKILL.md docs/property-assessor.md docs/web-automation.md docs/plans/2026-03-28-property-assessor-whatsapp-safe-runtime.md
|
||||
git commit -m "fix: make property-assessor safer for whatsapp runs"
|
||||
```
|
||||
@@ -67,6 +67,9 @@ Operational rule:
|
||||
- Preliminary helper output should be treated as structured scaffolding for the remaining work, not as a reason to stop and wait for another user nudge.
|
||||
- In chat/messaging runs, do not waste the turn on `npm install` or `npm ci` when the local skill dependencies are already present.
|
||||
- If the user asks `update?` or `and?` mid-run, treat that as a status request and continue the same assessment rather than restarting or stopping at the last checkpoint.
|
||||
- In WhatsApp or similar messaging runs, keep the core analysis on native `web_search`, `web_fetch`, and bounded browser actions. Do not make helper subprocesses the default path for discovery, CAD lookup, or photo extraction.
|
||||
- In those messaging runs, reserve subprocess use for a single final `render-report` attempt after the verdict and fair-value range are complete.
|
||||
- If final PDF render/send fails, return the completed decision-grade report in chat and report delivery failure separately rather than restarting the whole assessment.
|
||||
|
||||
### `assess`
|
||||
|
||||
@@ -84,6 +87,7 @@ Current behavior:
|
||||
- automatically tries to discover Zillow and HAR listing URLs from the address when no listing URL is provided
|
||||
- runs Zillow photo extraction first, then HAR as fallback when available
|
||||
- reuses the OpenClaw web-automation logic in-process instead of spawning nested helper commands
|
||||
- fails fast when Zillow/HAR discovery or photo extraction stalls instead of hanging indefinitely
|
||||
- returns a structured preliminary report payload
|
||||
- does not require recipient email(s) for the analysis-only run
|
||||
- asks for recipient email(s) only when PDF rendering is explicitly requested
|
||||
@@ -226,7 +230,9 @@ When those extractors return `imageUrls`, that returned set is the photo-review
|
||||
|
||||
## Approval-safe command shape
|
||||
|
||||
For chat-driven runs, prefer file-based commands.
|
||||
For local/manual runs, prefer file-based commands.
|
||||
|
||||
For chat-driven messaging runs, prefer native `web_search`, `web_fetch`, and bounded browser actions first. Treat these commands as local/manual helpers or non-chat fallbacks, not as the default core-analysis path.
|
||||
|
||||
Good:
|
||||
|
||||
@@ -240,6 +246,13 @@ Good:
|
||||
- `scripts/property-assessor render-report --input ... --output ...`
|
||||
- `web_fetch` to read an official CAD / assessor page when the TypeScript helper needs a plain page fetch
|
||||
|
||||
Messaging default:
|
||||
|
||||
- `web_search` to discover listing and public-record URLs
|
||||
- `web_fetch` for official CAD / assessor pages and accessible listing pages
|
||||
- bounded `web-automation` actions for rendered listing/photo views
|
||||
- one final `scripts/property-assessor render-report ...` attempt only after the decision-grade report is complete
|
||||
|
||||
Avoid when possible:
|
||||
|
||||
- `node -e "..."`
|
||||
|
||||
@@ -18,6 +18,11 @@ Automated web browsing and scraping using Playwright-compatible CloakBrowser, wi
|
||||
- Use `node skills/web-automation/scripts/zillow-discover.js "<street-address>"` or `har-discover.js` to resolve a real-estate listing URL from an address
|
||||
- Use `node skills/web-automation/scripts/zillow-photos.js "<listing-url>"` or `har-photos.js` for real-estate photo extraction before attempting generic gallery automation
|
||||
|
||||
Messaging rule:
|
||||
- For WhatsApp or similar chat-driven runs, prefer native `web_search`, `web_fetch`, and bounded browser actions over shelling out to helper scripts for every core step.
|
||||
- Treat the dedicated Zillow/HAR scripts as local/manual helpers, regression checks, or non-chat fallbacks.
|
||||
- If a messaging workflow needs a subprocess at all, reserve it for a single final delivery step rather than the whole assessment.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 20+
|
||||
@@ -148,6 +153,7 @@ What it does:
|
||||
- resolves directly to a property page when Zillow supports the address slug
|
||||
- otherwise looks for a `homedetails` listing link in the rendered page
|
||||
- returns the discovered listing URL as JSON
|
||||
- fails fast with a timeout if the browser-backed discovery stalls
|
||||
|
||||
### HAR discovery
|
||||
|
||||
@@ -161,6 +167,7 @@ What it does:
|
||||
- looks for a confident `homedetail` match in rendered results
|
||||
- returns the discovered listing URL when HAR exposes a strong enough match
|
||||
- returns `listingUrl: null` when HAR discovery is not confident enough
|
||||
- fails fast with a timeout if the browser-backed discovery stalls
|
||||
|
||||
### Zillow
|
||||
|
||||
@@ -174,6 +181,7 @@ What it does:
|
||||
- tries the `See all photos` / `See all X photos` entry point
|
||||
- if Zillow keeps the click path flaky, falls back to the listing's embedded `__NEXT_DATA__` payload
|
||||
- returns direct `photos.zillowstatic.com` image URLs as JSON
|
||||
- fails fast with a timeout if the browser-backed extraction stalls
|
||||
|
||||
Expected success shape:
|
||||
- `complete: true`
|
||||
@@ -191,6 +199,7 @@ What it does:
|
||||
- opens the HAR listing page
|
||||
- clicks `Show all photos` / `View all photos`
|
||||
- extracts the direct `pics.harstatic.com` image URLs from the all-photos page
|
||||
- fails fast with a timeout if the browser-backed extraction stalls
|
||||
|
||||
Expected success shape:
|
||||
- `complete: true`
|
||||
|
||||
Reference in New Issue
Block a user