Closes #15, #22, #24, #25. Closes #1 and #27 (already shipped in 0.2.0). ## CI/CD (#22) - .forgejo/workflows/ci.yml — Python lint (ruff) + pytest + Vue typecheck + vitest on every PR/push. Installs cf-core from GitHub mirror for the CI runner. - .forgejo/workflows/release.yml — Docker build/push (api + web) to Forgejo registry on v* tags; git-cliff changelog; multi-arch amd64+arm64. - .forgejo/workflows/mirror.yml — push to GitHub + Codeberg mirrors. ## Self-hosted installer (#25) - install.sh rewritten to match CF installer pattern: coloured output, named functions, --docker / --bare-metal / --help flags, auto-detect Docker/conda/ Python/Node/Chromium/Xvfb, license key prompting with format validation. ## Nginx docs (#24) - docs/nginx-self-hosted.conf — sample nginx config: SPA fallback, SSE proxy (proxy_buffering off), long-term asset cache headers. - docs/getting-started/installation.md — bare-metal install section with nginx setup, Chromium/Xvfb note, serve-ui.sh vs nginx trade-off. ## cf-orch agent (#15) - compose.override.yml — cf-orch-agent sidecar service (profiles: [orch]). Starts only with docker compose --profile orch. Registers with coordinator at CF_ORCH_COORDINATOR_URL (default 10.1.10.71:7700). - .env.example — CF_ORCH_URL / CF_ORCH_COORDINATOR_URL comments expanded. ## Docs - mkdocs.yml + full docs/ tree (getting-started, reference, user-guide) staged from prior session work. Bump version 0.2.0 → 0.3.0.
84 lines
2.5 KiB
Markdown
84 lines
2.5 KiB
Markdown
# Trust Score Algorithm
|
||
|
||
## Signal scoring
|
||
|
||
Each signal contributes 0–20 points to the composite score.
|
||
|
||
### account_age
|
||
|
||
| Days old | Score |
|
||
|----------|-------|
|
||
| < 7 | 0 (triggers `new_account` hard flag) |
|
||
| 7–30 | 5 |
|
||
| 30–90 | 10 |
|
||
| 90–365 | 15 |
|
||
| > 365 | 20 |
|
||
|
||
Data source: eBay profile page (BTF scraper via headed Chromium + Xvfb — eBay API does not expose account registration date).
|
||
|
||
### feedback_count
|
||
|
||
| Count | Score |
|
||
|-------|-------|
|
||
| 0 | 0 (triggers `zero_feedback` hard flag, score capped at 35) |
|
||
| 1–9 | 5 |
|
||
| 10–49 | 10 |
|
||
| 50–199 | 15 |
|
||
| 200+ | 20 |
|
||
|
||
### feedback_ratio
|
||
|
||
| Ratio | Score |
|
||
|-------|-------|
|
||
| < 80% (with 20+ reviews) | 0 (triggers `established_bad_actor`) |
|
||
| < 90% | 5 |
|
||
| 90–94% | 10 |
|
||
| 95–98% | 15 |
|
||
| 99–100% | 20 |
|
||
|
||
### price_vs_market
|
||
|
||
Compares listing price to the median of recent completed sales from eBay Marketplace Insights API.
|
||
|
||
| Price vs. median | Score |
|
||
|-----------------|-------|
|
||
| < 40% | 0 (triggers `suspicious_price` flag) |
|
||
| 40–59% | 5 |
|
||
| 60–79% | 10 |
|
||
| 80–120% | 20 (normal range) |
|
||
| 121–149% | 15 |
|
||
| 150%+ | 10 |
|
||
|
||
`suspicious_price` flag is suppressed when the market price distribution is too wide (standard deviation > 50% of median) — this prevents false positives on heterogeneous search results.
|
||
|
||
When no market data is available, this signal returns `None` and is excluded from the composite.
|
||
|
||
### category_history
|
||
|
||
Derived from the seller's recent listing history (categories of their sold items):
|
||
|
||
| Result | Score |
|
||
|--------|-------|
|
||
| Seller has history in this category | 20 |
|
||
| Seller sells cross-category (generalist) | 10 |
|
||
| No category history available | None (excluded from composite) |
|
||
|
||
## Composite calculation
|
||
|
||
```
|
||
composite = (sum of available signal scores) / (20 × count of available signals) × 100
|
||
```
|
||
|
||
This ensures missing signals don't penalize a seller — only available signals count toward the denominator.
|
||
|
||
## Zero-feedback cap
|
||
|
||
When `feedback_count == 0`, the composite is hard-capped at **35** after the standard calculation. A 0-feedback seller cannot score above 35 regardless of other signals.
|
||
|
||
## Partial scores
|
||
|
||
A score is marked **partial** when one or more signals are `None` (not yet available). The score is recalculated and the partial flag is cleared when enrichment completes.
|
||
|
||
## Red flag override
|
||
|
||
Red flags are evaluated independently of the composite score. A seller can have a high composite score and still trigger red flags — for example, a long-established seller with a suspicious-priced listing and duplicate photos.
|