לאמת שהעלאה באמת עלתה, בלי דפדפן

אחרי דחיפה לאוויר צריך לדעת אם השינוי באמת שם. הבדיקה נראית פשוטה, ויש בה שלוש מלכודות שכולן מחזירות תשובה שנראית בדיוק כמו התוצאה הנכונה: עברית שמופיעה בבנדל בשתי צורות שונות, מחרוזת חיפוש שנבלעת ב-shell ומחזירה התאמה לכל שורה בקובץ, ומחרוזת שאינה ייחודית לשינוי. ה-Skill הזה נותן את שיטת האימות שעובדת בלי לפתוח דפדפן, ואת האזהרה שמונעת חסימה של האתר בגלל יותר מדי בקשות אוטומטיות. זהו Skill ל-Claude: תיקייה עם קובץ SKILL.md, שנטענת אוטומטית כשהמשימה מתאימה לתיאור שבראש הקובץ. בניגוד לפרומפט שמדביקים בכל פעם מחדש, Skill מותקן פעם אחת וממשיך לעבוד לבד.

קוד ואיכות · פריסה · Vercel · אימות · curl · בנדל

מתי הוא נכנס לפעולה

---
name: deploy-verify
description: "Verify that a deployed change is actually live on a static or Vercel site without opening a browser, using curl and a search inside the built bundle. Covers the Hebrew encoding trap, the shell escaping trap that fakes success, and why flooding the site with requests looks like an outage. Use when a change has just been pushed, when asked whether something is already deployed, or when a deploy looks broken but may not be."
---

# לאמת פריסה בלי דפדפן

## שלוש דרכים לקבל תשובה שגויה

כולן נראות בדיוק כמו התוצאה הנכונה. זו הסיבה שהקובץ הזה קיים.

### 1. עברית מופיעה בבנדל בשתי צורות

לפעמים כטקסט רגיל, ולפעמים כרצף `\uXXXX` **באותיות גדולות**. חיפוש
בצורה אחת בלבד מחזיר "הפריסה נכשלה" על פריסה מוצלחת לחלוטין.

תמיד לבדוק את שתיהן:

```js
const enc = (s) => [...s].map((c) =>
  c.charCodeAt(0) > 127
    ? '\\u' + c.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')
    : c).join('')

const ok = js.includes(phrase) || js.includes(enc(phrase))
```

### 2. בניית מחרוזת מקודדת בשורת הפקודה

ה-shell בולע את הבקסלשים, המשתנה יוצא ריק, ו-`grep -c ""` מחזיר את
מספר **כל השורות בקובץ**. כך התקבל דיווח על אלפי התאמות בחיפוש של כלום.

**לכתוב סקריפט לקובץ ולהריץ אותו.** לא פקודה חד שורתית עם עברית או עם
בקסלשים.

### 3. מחרוזת שאינה ייחודית לשינוי

ביטוי שמופיע גם במקום אחר גורם לבדיקה לדווח שההסרה נכשלה, בזמן שהיא
הצליחה.

לבחור מחרוזת שקיימת רק בשינוי הזה, **ולבדוק גם את הכיוון ההפוך**: שהנוסח
הישן נעלם.

## הבדיקה שעובדת

```js
const html = await fetch('https://example.com/', {
  headers: { 'User-Agent': 'Mozilla/5.0 Chrome/124' },
}).then((r) => r.text())

const name = html.match(/assets\/index-[A-Za-z0-9_-]*\.js/)[0]
const js = await fetch('https://example.com/' + name).then((r) => r.text())

for (const [label, s, want] of [
  ['הנוסח החדש', 'המחרוזת החדשה', true],
  ['הנוסח הישן', 'המחרוזת הישנה', false],
]) {
  const has = js.includes(s) || js.includes(enc(s))
  console.log(label, has === want ? 'תקין' : 'נכשל')
}
```

## השוואת שמות הקבצים

שם הקובץ **עשוי** להיות שונה באופן לגיטימי, כי פלטפורמת הבנייה עובדת עם
משתני סביבה משלה. לכן שם שונה אינו הוכחה לכישלון. כשהשמות כן יוצאים
זהים, השוואת תוכן בית-בית היא אימות מלא בבקשה אחת.

**האימות החזק הוא לפי תוכן, לא לפי שם.**

## אזהרה: לא להציף את האתר

סריקה של עשרות כתובות ברצף, או לולאה שמושכת שוב ושוב, מפעילה את ההגנה
האוטומטית של פלטפורמות אירוח ומחזירה שגיאת חסימה **לכל כתובת מאותו IP**.
זה נראה בדיוק כמו אתר שנפל, ומבזבז שעה על אבחון תקלה שאתם יצרתם.

לאמת בבקשה אחת אחרי המתנה. לסריקה של הרבה עמודים, לעבוד על תיקיית
הבנייה המקומית ולא על האתר החי.

## אתר עם service worker

אתר שמאחסן מראש עשרות מגהבייט מקריס חלוניות דפדפן מוטמעות. לאמת עם
בקשות רשת בלבד.

וגולש חוזר מקבל את הגרסה מהמטמון עד שה-service worker מתעדכן. "אני לא
רואה את השינוי" אצל המשתמש אינו בהכרח פריסה שנכשלה.

## קוד יציאה אפס אינו הצלחה

פקודה שרצה ברקע יכולה להחזיר אפס, לייצר קובץ ריק, ובגוף הפלט לכתוב
שהעבודה נכשלה. קוד היציאה תיאר את העטיפה, לא את העבודה.

**תמיד לאמת שהתוצר עצמו קיים**, ולא להסתמך על קוד יציאה או על הודעת
סיום.

איך מתקינים

  1. צרו תיקייה בשם deploy-verify בתוך ‎.claude/skills/‎ בפרויקט, או בתיקיית הבית לשימוש בכל הפרויקטים.
  2. שמרו בתוכה את הקובץ בשם SKILL.md.
  3. זהו. אין צורך להפעיל כלום, והוא ייטען לבד כשהמשימה תתאים לתיאור.