You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
authored
fix(production-scan): stop silent Stage-4 skip — locate renderer up front + make publish mandatory (#36)
A trial scanned a public repo but skipped report render + S3 upload, wrongly
concluding "there is no callable uploader" even though render-report.mjs was in
its checkout, and ended with neither a hosted URL nor an honest upload-failed line.
Two SKILL.md-only changes:
- Stage 1.1a preflight: locate render-report.mjs on disk (cwd is the scanned repo,
not the skill) and derive SKILL_DIR up front, while context is short — so the agent
cannot later claim the uploader is absent. Graceful when truly missing: finish the
scan, emit the honest upload-failed line, don't abort.
- honest-URL rule: for a public repo, publishing is mandatory; ending with only an
in-chat summary is a FAILED run. Forbid skipping publish on a belief, and allow the
upload-failed line only after a real non-zero exit quoting the real error. Carve out
the Stage 4.1 public-repo gate as the one legitimate no-publish path.
Prose-only; render smoke test unchanged (17/17).
Co-authored-by: Gandy2025 <gandyxiong@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .claude/skills/production-scan/SKILL.md
+44Lines changed: 44 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -270,6 +270,26 @@ file would be useless. So:
270
270
- `📄 **Hosted report:** https://report.first-tree.ai/<report_key>.html` — expires in 7 days (both uploads succeeded)
271
271
- `⚠️ **Report upload failed:** <one-line cause> — hosted link temporarily unavailable, re-run the scan to retry` (publish failed)
272
272
273
+
**Finishing the scan means emitting one of those two lines — for a public repo, publishing
274
+
is mandatory, not optional.** Ending the turn with only the in-chat findings summary and *no*
275
+
final line is a **FAILED, incomplete run**, not a lighter kind of success. Two rules keep that
276
+
failure unreachable by mistake:
277
+
278
+
- **Never skip publish on a belief.** "There's no uploader / no renderer / no credentials, so
279
+
I'll stop" is not a valid outcome and is almost always wrong: the renderer
280
+
(`scripts/render-report.mjs`) **ships in this skill** and you located it at the step 1.1a
281
+
preflight; the S3 credentials come from the runtime env (see **CONTRACT: S3 publish**). If a
282
+
publish step *seems* impossible, re-resolve the skill dir and re-read the contract — do not
283
+
abandon publishing.
284
+
- **Only a real non-zero exit earns the failure line.** Emit the `⚠️ Report upload failed` line
285
+
**only after** the renderer or an `aws s3 cp` command has actually run and returned non-zero,
286
+
and make `<one-line cause>` quote that real error (e.g. the actual `aws` stderr) — never a guess
287
+
or a hunch that it "wouldn't work".
288
+
289
+
(The one legitimate no-publish path is the Stage 4.1 step-0 public-repo gate: if the repo can't be
290
+
confirmed public, you fail closed — keep the report in-chat only and say so plainly. That is a
291
+
stated outcome, not a silent skip.)
292
+
273
293
## Voice register (NORMATIVE: load this BEFORE writing any human-facing string)
274
294
275
295
This register governs **every human-facing string** the scan emits — `verdict_quip`,
@@ -527,6 +547,30 @@ owner="${rest##*[:/]}" # last segment after the final ':' or '/' = owner
527
547
and dependencies: module greps sweep the on-disk tree, so total bytes bound the
528
548
real workload regardless of what git tracks.
529
549
550
+
**Preflight — LOCATE the publish toolchain now, before the heavy scan (while context is
551
+
still short):** the renderer that Stage 3 runs and Stage 4 uploads ships *inside this
552
+
skill*, but your cwd is the *scanned* repo, not the skill — so find the renderer on disk
553
+
and derive its directory, rather than assuming a path:
554
+
555
+
```bash
556
+
# cwd here is the SCANNED repo, not this skill. Locate the renderer under the
557
+
# launch-readiness-scan clone you made at kickoff ($HOME is a safe wide fallback), then
558
+
# derive SKILL_DIR (= .../production-scan) from where it actually is:
559
+
RENDERER="$(find "$HOME" -type f -path '*/production-scan/scripts/render-report.mjs' 2>/dev/null | head -1)"
560
+
if [ -n "$RENDERER" ]; then
561
+
SKILL_DIR="$(cd "$(dirname "$RENDERER")/.." && pwd)" # absolute path of this skill's dir
562
+
echo "renderer OK — SKILL_DIR=$SKILL_DIR"
563
+
else
564
+
echo "WARN: renderer not found under \$HOME — still finish the scan and deliver the in-chat report; publishing may be unavailable, so end with the honest upload-failed line (do NOT abort before findings exist)."
565
+
fi
566
+
```
567
+
568
+
Record the resolved absolute `SKILL_DIR` and **substitute it for `<skill-dir>`** in the
569
+
Stage 3 (render) and Stage 4 (publish) commands (a later shell won't inherit the variable —
570
+
use the resolved path). Because the renderer is now **located from the real filesystem**, a
571
+
later conclusion that "there is no uploader/renderer, so I'll skip publishing" is a mistake,
572
+
never a fact: re-run this search and proceed — don't abandon the publish.
573
+
530
574
#### 1.1b — Repository size detection
531
575
532
576
Scan depth is decided by **exactly one variable: the total file count** (every
0 commit comments