Pipeline run
d6c35e6e-fb0d-4299-9ee2-59d7a5bec9c0
Pipeline LLM cost (USD)
API 1: $0.0010
API 2: $0.0000
API 3: $0.0000
Total: $0.0010
Client output enrichment
v2 Skill cluster · Nature of work · AI index · Tech stack maturity · Evidence · KRA description
SPARSE JD
Nature of work
—
Tech stack maturity
Mainstream Modern
AI index (0 = no AI use, 5 = totally AI-dependent · v2.1)
0.00 / 5
· Title match
· Has AI skill
· AI skill (primary)
· AI skill (secondary)
· On AI team
· Builds AI products
vocab breakdown (legacy)
Assistants (×1):
—
Frameworks (×2):
—
Models / concepts (×3):
—
Evidence — skills matched in JD (0)
Skill cluster (0 dimension groups, role-scoped)
Status:
extract_from_jd_done
Created: 2026-08-20T15:33:56.490025Z
Updated: 2026-08-20T15:35:23.530426Z
Flow
Current 3-step pipeline
1 POST /skills/extract-from-jd
2 POST /skills/extract-details
3 POST /skills/final-role-output
Role
Chosen role & resolution
No chosen role stored for this run.
Job description
Fix candidate photos disappearing on ranked list and route candidate avatars through Next image optimizer Photo CDN was returning 429s when all candidate rows remounted at once after navigating back from the detailed candidate page. Google and LinkedIn serve profile pictures no-cache and throttle repeated bursts, so the browser was re-requesting every single photo fresh on each mount and hitting the rate limit. The img error handler would fire, fall through to initials, and stay there because the browser cached the failed 429 response. Switched CandidatePhoto from a plain img element to Next's built-in image optimizer. The optimizer fetches each URL once server-side, caches it under our origin for a week (minimumCacheTTL in next.config.ts), and serves it from there — so going back to the ranked list is a local cache hit and the CDN is never hit again. Verified: first request MISS, second request HIT with Cache-Control max-age=604800. Also unified the fallback. When a photo genuinely fails, it now shows the same deterministic gradient avatar (keyed to the candidate's name) that candidates without any photo get — so rows never flip between two different avatar styles and the same person always gets the same colour. Updated candidate-row-wide, candidate-profile and app-rail to pass the name prop so the fallback gradient is consistent everywhere.
Library artifacts (this run)
No artifact rows for this run.
nano JD Parser — gpt-4.1-nano click to toggle
JD type
fail
Show raw JSON
{
"JD_type": "fail"
}
API 1 — extract-from-jd click to toggle
{
"final_skills": [],
"jd_parameters": null,
"jd_role": {
"display_name": "\u2014",
"rationale": "Stage 1 marked JD_type=fail (unparseable); body has only 0 canonical-skill mentions and 0 tech-marker hits \u2014 insufficient evidence",
"role_aliases": [],
"role_archetype": "\u2014",
"slug": ""
},
"nano_parsed": {
"JD_type": "fail"
},
"rejected": true,
"rejection_reason": "Stage 1 marked JD_type=fail (unparseable); body has only 0 canonical-skill mentions and 0 tech-marker hits \u2014 insufficient evidence",
"role": null,
"run_id": null,
"secondary_skills": [],
"skill_layers": null,
"stage3_signals": null,
"stage4_decision": null,
"stage5_updates": null
}
API 2 — extract-details
{}
API 3 — final-role-output
{}
LLM Calls
Every model call made for this run, in pipeline order. Click a card to see the model's response.
Loading…