Skip to content

Commit 8f308fe

Browse files
Gandy2025gandyxiong01claude
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>
1 parent 2dff603 commit 8f308fe

1 file changed

Lines changed: 44 additions & 0 deletions

File tree

‎.claude/skills/production-scan/SKILL.md‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,26 @@ file would be useless. So:
270270
- `📄 **Hosted report:** https://report.first-tree.ai/<report_key>.html` — expires in 7 days (both uploads succeeded)
271271
- `⚠️ **Report upload failed:** <one-line cause> — hosted link temporarily unavailable, re-run the scan to retry` (publish failed)
272272
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+
273293
## Voice register (NORMATIVE: load this BEFORE writing any human-facing string)
274294
275295
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
527547
and dependencies: module greps sweep the on-disk tree, so total bytes bound the
528548
real workload regardless of what git tracks.
529549
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+
530574
#### 1.1b — Repository size detection
531575
532576
Scan depth is decided by **exactly one variable: the total file count** (every

0 commit comments

Comments
 (0)