Skip to content

fix(#3069): fall back to workspace scripts dir for script companions#3393

Merged
waynesun09 merged 1 commit into
mainfrom
postrun-command
Jul 8, 2026
Merged

fix(#3069): fall back to workspace scripts dir for script companions#3393
waynesun09 merged 1 commit into
mainfrom
postrun-command

Conversation

@waynesun09

@waynesun09 waynesun09 commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary

  • Fixes pre-commit tool auto-install and fix-agent PR summaries silently failing once pre-code.sh/pre-fix.sh/post-code.sh/post-fix.sh are resolved from a URL base (e.g. fullsend-ai/agents) instead of the local scaffold checkout.
  • Adds a workspace-directory fallback for companion-file lookup in the four scripts — no new CLI surface, no Go changes (per review feedback, this replaces the earlier fullsend postrun subcommand approach).
  • Warns instead of silently skipping when companions are missing everywhere, so the failure no longer surfaces only as a confusing Executable X not found at the pre-commit gate.

Related Issue

Fixes #3069
Fixes #3070

Root cause

The scripts locate their companions (resolve-precommit-tools.py, install-precommit-tools.sh, process-fix-result.py) next to BASH_SOURCE[0]. That worked while scripts lived in the local scaffold checkout, but the harness fetches URL-based scripts as single flat files into the content-addressed cache (fetchBaseFile in internal/harness/compose.go) with no sibling-file concept — so once post-code.sh/post-fix.sh moved to URL resolution, the sibling lookups silently missed and the whole install step was skipped.

The companions were never really "sibling files of an agent script": the reusable workflows' "Prepare workspace" step unconditionally materializes the full scripts/ directory (with L1 org overrides applied) at a known workspace path on every job — ${GITHUB_WORKSPACE}/scripts/ (per-org) or ${GITHUB_WORKSPACE}/.fullsend/scripts/ (per-repo). Only the BASH_SOURCE-derived guess at where that copy lives was broken.

Changes

internal/scaffold/fullsend-repo/scripts/{pre-code,pre-fix,post-code,post-fix}.sh:

Because the fallback executes the workspace copy, resolve-precommit-tools.py finds the L1-overridden .pre-commit-tools.yaml next to itself (__file__), so org registry overrides keep working from the cache path too.

Testing

  • bash -n and shellcheck (via make lint) clean on all four scripts
  • Existing pre-code-test.sh / post-code-test.sh / post-fix-test.sh suites pass
  • Isolated smoke test of the fallback block in 5 scenarios: co-located siblings (no fallback taken), URL-cache + per-org (resolves $GITHUB_WORKSPACE/scripts), URL-cache + per-repo (resolves $GITHUB_WORKSPACE/.fullsend/scripts), companions missing everywhere (warning fires, graceful skip), GITHUB_WORKSPACE unset for local runs (safe via :-, no error)
  • Post-script companion scripts not accessible when resolved from URL-based cache #3069 validation criteria 1–3 (live agent run auto-installing lychee from the cache path) require a post-merge workflow run

Checklist

  • PR title follows Conventional Commits
  • Commits are signed off (DCO)
  • I wrote this contribution myself and can explain all changes in it

Note: this rework removes the sequencing dependency on a fullsend release — the companion fullsend-ai/agents PR no longer needs to wait for a new subcommand to ship, since post-code.sh/post-fix.sh fetched from fullsend-ai/agents will find the companions via the workspace fallback.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 5:54 PM UTC · Completed 6:08 PM UTC
Commit: 023a190 · View workflow run →

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add fullsend postrun subcommands for pre-commit installs and fix summaries

🐞 Bug fix ✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Move runner post-script logic into fullsend postrun to avoid URL-fetched sibling script
 failures.
• Auto-resolve/install pre-commit hook tool dependencies from registry + per-repo overrides.
• Render/post fix-agent fix-result.json as a PR comment with safe, non-fatal posting semantics.
Diagram

graph TD
A["Scaffold pre/post scripts"] --> B["fullsend CLI: postrun"] --> C["precommit-install"] --> D["Tools registry YAML"]
B --> E["fix-summary"] --> F["GitHub API"]
C --> G["~/.local/bin install dir"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Teach harness to fetch script directories (sibling files)
  • ➕ Keeps logic in scripts; no Go porting effort
  • ➕ May help other future script bundles that assume sibling files
  • ➖ Increases harness complexity and surface area for caching/extraction semantics
  • ➖ Still leaves critical runner checks dependent on correct remote packaging/layout
  • ➖ Doesn’t address duplication between script logic and CLI behaviors
2. Embed companion scripts into scaffold fetch as a single archive
  • ➕ Preserves existing Python/Bash logic with minimal changes
  • ➕ Avoids modifying harness resolution rules if archive is always available
  • ➖ Adds a new distribution mechanism (archive build/versioning)
  • ➖ More moving parts than invoking the already-present fullsend binary
  • ➖ Still splits core behavior across languages with separate test stacks
3. Keep scripts but vendor the logic directly into post-code.sh/post-fix.sh
  • ➕ No new CLI surface area
  • ➕ No dependency on sibling files
  • ➖ Large, hard-to-test shell scripts; reintroduces supply-chain and parsing pitfalls
  • ➖ Difficult to share with other integrations and keep consistent
  • ➖ Less maintainable than Go + unit tests

Recommendation: The PR’s approach (move runner-critical logic into the fullsend binary) is the most robust: fullsend is already present on the runner, avoids sibling-file assumptions when scripts are URL-fetched, and consolidates behavior under unit-tested Go code. The main tradeoff is increased CLI surface area, but it’s justified for reliability and maintainability.

Files changed (13) +2044 / -95

Enhancement (4) +930 / -0
postrun.goIntroduce 'fullsend postrun' parent Cobra command +40/-0

Introduce 'fullsend postrun' parent Cobra command

• Adds a new 'postrun' command group intended for runner-side post-sandbox steps. Registers 'precommit-install' and 'fix-summary' subcommands and documents the rationale for moving logic into the binary.

internal/cli/postrun.go

postrun_fixsummary.goAdd 'postrun fix-summary' to render/post fix-agent PR comments +230/-0

Add 'postrun fix-summary' to render/post fix-agent PR comments

• Ports fix-result.json processing and markdown rendering from Python into Go. Posts PR comments via the GitHub forge client, truncates at 32KB, and uses a distinct exit code (2) for non-fatal posting failures.

internal/cli/postrun_fixsummary.go

postrun_precommit.goAdd 'postrun precommit-install' to resolve/install pre-commit tool deps +659/-0

Add 'postrun precommit-install' to resolve/install pre-commit tool deps

• Ports registry merge + hook resolution logic and implements installers for binary (checksum-verified tarballs), apt, pip, and npm. Supports embedded default registry with optional org-level override path and additive per-repo registry merging.

internal/cli/postrun_precommit.go

root.goRegister new 'postrun' command on CLI root +1/-0

Register new 'postrun' command on CLI root

• Adds 'newPostrunCmd()' to the root Cobra command so runner scripts can invoke 'fullsend postrun ...'.

internal/cli/root.go

Bug fix (4) +24 / -86
post-code.shSwitch pre-commit tool auto-install to 'fullsend postrun precommit-install' +5/-18

Switch pre-commit tool auto-install to 'fullsend postrun precommit-install'

• Removes dirname-relative lookup of companion resolver/installer scripts and instead invokes the new CLI subcommand, passing a base-branch local registry when available.

internal/scaffold/fullsend-repo/scripts/post-code.sh

post-fix.shUse 'fullsend postrun' for pre-commit install and fix summary posting +8/-27

Use 'fullsend postrun' for pre-commit install and fix summary posting

• Replaces both the resolver/installer sibling-script invocation and the fix-result processor script with 'fullsend postrun precommit-install' and 'fullsend postrun fix-summary'. Preserves prior semantics of treating comment-post failures as non-fatal.

internal/scaffold/fullsend-repo/scripts/post-fix.sh

pre-code.shSwitch best-effort pre-install step to 'fullsend postrun precommit-install' +6/-21

Switch best-effort pre-install step to 'fullsend postrun precommit-install'

• Removes dependency on sibling scripts and calls the new 'postrun precommit-install' subcommand against the target repo, optionally merging base-branch .pre-commit-tools.yaml overrides.

internal/scaffold/fullsend-repo/scripts/pre-code.sh

pre-fix.shSwitch best-effort pre-install step to 'fullsend postrun precommit-install' +5/-20

Switch best-effort pre-install step to 'fullsend postrun precommit-install'

• Updates the pre-fix runner script to invoke the new CLI subcommand and eliminates dirname-relative companion-script paths, matching the post-fix behavior.

internal/scaffold/fullsend-repo/scripts/pre-fix.sh

Tests (2) +1085 / -0
postrun_fixsummary_test.goUnit tests for fix-summary markdown rendering and exit-code behavior +144/-0

Unit tests for fix-summary markdown rendering and exit-code behavior

• Covers default behaviors, fixed/disagreed sections, decision points rendering, truncation warnings, dry-run behavior, and required flag registration.

internal/cli/postrun_fixsummary_test.go

postrun_precommit_test.goComprehensive tests for registry merge/resolve and install helpers +941/-0

Comprehensive tests for registry merge/resolve and install helpers

• Ports Python resolver test coverage to Go and adds integration-style tests for config parsing, local registry merge, checksum verification, tar extraction, and download behavior using httptest.

internal/cli/postrun_precommit_test.go

Documentation (1) +5 / -6
.pre-commit-tools.yamlUpdate registry comments to reference 'fullsend postrun precommit-install' +5/-6

Update registry comments to reference 'fullsend postrun precommit-install'

• Rewords documentation to match the new execution model where 'fullsend' resolves and installs tools directly from the YAML registry.

internal/scaffold/fullsend-repo/scripts/.pre-commit-tools.yaml

Other (2) +0 / -3
MakefileRemove retired Python fix-result test from script-test target +0/-1

Remove retired Python fix-result test from script-test target

• Drops 'process-fix-result-test.py' from the 'script-test' Makefile target to reflect the migration away from the legacy Python implementation.

Makefile

scaffold.goStop marking retired companion scripts as scaffold executables +0/-2

Stop marking retired companion scripts as scaffold executables

• Removes 'install-precommit-tools.sh' and 'resolve-precommit-tools.py' from the scaffold executable file list since the scripts are deleted and replaced by Go subcommands.

internal/scaffold/scaffold.go

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Site preview

Preview: https://7162f8e8-site.fullsend-ai.workers.dev

Commit: fa96e95d27b76188dce31f3f53573f6753519425

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@qodo-code-review

qodo-code-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 61 rules

Grey Divider


Action required

1. postFixSummary() constructs gh.New() ✓ Resolved 📘 Rule violation ⌂ Architecture
Description
postFixSummary() constructs a concrete GitHub client via gh.New(token) instead of receiving a
forge.Client via dependency injection. This tightly couples internal/cli to a specific forge
implementation and violates the forge-abstraction requirement.
Code

internal/cli/postrun_fixsummary.go[R210-223]

+func postFixSummary(ctx context.Context, owner, repo string, pr int, body, token string, dryRun bool, printer *ui.Printer) error {
+	if len(body) > maxFixSummaryCommentLength {
+		truncationNotice := "\n\n*[truncated — output exceeded 32KB]*"
+		printer.StepWarn(fmt.Sprintf("comment body truncated from %d to %d chars", len(body), maxFixSummaryCommentLength))
+		body = body[:maxFixSummaryCommentLength-len(truncationNotice)] + truncationNotice
+	}
+
+	if dryRun {
+		printer.StepInfo(fmt.Sprintf("[dry-run] Would post PR summary (%d chars)", len(body)))
+		return nil
+	}
+
+	client := gh.New(token)
+	comment, err := client.CreateIssueComment(ctx, owner, repo, pr, body)
Relevance

⭐⭐⭐ High

Team has accepted forge-neutral CLI layering; moved GitHub-specific details out of internal/cli into
forge client (PR #2415).

PR-#2415
PR-#383

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1062052 requires new forge operations to use the forge.Client interface via
dependency injection. The changed code constructs a concrete GitHub client (gh.New(token)) inside
postFixSummary() and immediately uses it to post a PR comment, bypassing DI of forge.Client.

Rule 1062052: Route all git forge operations through forge.Client
internal/cli/postrun_fixsummary.go[210-223]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`internal/cli/postrun_fixsummary.go` creates a concrete GitHub client (`gh.New(token)`) inside `postFixSummary()`. The compliance rule requires routing forge operations through the `forge.Client` interface and passing it via dependency injection rather than constructing a forge-specific client in the call site.

## Issue Context
`gh.New(token)` returns a GitHub-specific implementation. Refactor so `postFixSummary()` depends on the `internal/forge` interface (`forge.Client`), with the concrete client created at the command wiring layer and injected.

## Fix Focus Areas
- internal/cli/postrun_fixsummary.go[210-229]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Registry overrides ignored ✓ Resolved 🐞 Bug ≡ Correctness
Description
loadRegistry always falls back to the embedded scripts/.pre-commit-tools.yaml unless
--registry is explicitly provided, despite the flag help/docs indicating an on-runner
scripts/.pre-commit-tools.yaml overlay should be used when present. Because the scaffold
post-script invokes fullsend postrun precommit-install without --registry, L1 org/per-repo
registry replacements won’t apply and required tools may not be installed.
Code

internal/cli/postrun_precommit.go[R188-198]

+	if explicitPath != "" {
+		data, err = os.ReadFile(explicitPath)
+		if err != nil {
+			return toolRegistry{}, fmt.Errorf("reading registry %s: %w", explicitPath, err)
+		}
+	} else {
+		data, err = scaffold.FullsendRepoFile("scripts/.pre-commit-tools.yaml")
+		if err != nil {
+			return toolRegistry{}, fmt.Errorf("loading embedded registry: %w", err)
+		}
+	}
Relevance

⭐⭐ Medium

No strong historical evidence on registry overlay behavior; no prior accepted/rejected findings
matching loadRegistry default/overlay semantics found.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The command help text and docs state an on-runner scripts/.pre-commit-tools.yaml may replace
upstream defaults (L1 overlay), but loadRegistry only reads from --registry or the embedded
scaffold. The updated post-script invokes precommit-install without --registry, so the
filesystem overlay cannot take effect.

internal/cli/postrun_precommit.go[85-114]
internal/cli/postrun_precommit.go[179-205]
internal/scaffold/fullsend-repo/scripts/post-code.sh[266-276]
docs/guides/user/customizing-agents.md[206-226]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`fullsend postrun precommit-install` is intended to pick up the L1 registry replacement that is materialized onto the runner filesystem (overlay) at `scripts/.pre-commit-tools.yaml`, but `loadRegistry()` ignores the filesystem unless `--registry` is explicitly set. The scaffold post-scripts call the subcommand without `--registry`, so L1 overrides are silently skipped.

### Issue Context
- The CLI help text says the registry can be “materialized at --registry (defaults to scripts/.pre-commit-tools.yaml under the prepared workspace)”.
- Docs describe L1 replacement via overlay (customized/scripts/.pre-commit-tools.yaml) which should land as `scripts/.pre-commit-tools.yaml` at runtime.
- Current implementation only uses the embedded registry when `--registry` is empty.

### Fix Focus Areas
- internal/cli/postrun_precommit.go[85-114]
- internal/cli/postrun_precommit.go[179-205]
- internal/scaffold/fullsend-repo/scripts/post-code.sh[269-276]
- internal/scaffold/fullsend-repo/scripts/post-fix.sh[181-188]
- internal/scaffold/fullsend-repo/scripts/pre-code.sh[130-139]
- internal/scaffold/fullsend-repo/scripts/pre-fix.sh[110-122]

### Implementation notes
- In `loadRegistry(explicitPath string)`, when `explicitPath == ""`, first check for a readable filesystem file at `scripts/.pre-commit-tools.yaml` (relative to the current working directory / prepared workspace root). If present, read it; otherwise fall back to the embedded registry.
- Consider also updating the scaffold scripts to pass `--registry scripts/.pre-commit-tools.yaml` explicitly for clarity/robustness (even if `loadRegistry` gains the fallback), so behavior is stable if working directory assumptions change.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Untrusted warnings unsanitized ✓ Resolved 🐞 Bug ⛨ Security
Description
runPrecommitInstall prints warnings derived from .pre-commit-config.yaml hook fields without
stripping newlines or GitHub Actions workflow-command markers (::). This can allow untrusted repo
content to break log structure and (if a newline precedes ::…) potentially emit workflow-command
markers on their own line.
Code

internal/cli/postrun_precommit.go[R159-162]

+	installs, warnings := resolveTools(config, registry)
+	for _, w := range warnings {
+		printer.StepWarn(w)
+	}
Relevance

⭐⭐ Medium

Mixed history on GHA command/newline sanitization: accepted in some scripts/transcript paths (PR
#2306/#764) but similar suggestions rejected elsewhere (PR #2395).

PR-#2306
PR-#2395
PR-#764

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Warnings are constructed directly from hook fields and printed without modification. The UI printer
emits the text verbatim, and the repo’s existing sanitizer explicitly targets GitHub Actions ::
markers and newline/control encodings—showing this is a known hazard for untrusted output in runner
logs.

internal/cli/postrun_precommit.go[159-162]
internal/cli/postrun_precommit.go[329-337]
internal/ui/ui.go[76-82]
internal/runtime/sanitize.go[11-28]
docs/guides/user/customizing-agents.md[263-266]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Runner-side `precommit-install` logs warnings that include untrusted strings (hook IDs / hook entry commands from `.pre-commit-config.yaml`). These warnings are printed via `ui.Printer.StepWarn` without sanitization. The repo already has a dedicated sanitizer for GitHub Actions workflow command markers and newline/control encodings, but it is not applied here.

### Issue Context
- `resolveTools` formats warnings using `hook.ID` and the first token of `hook.Entry`.
- These values come from YAML in the target repo working tree, which docs explicitly call untrusted in this runner-side pipeline.
- `ui.Printer.StepWarn` prints the provided text verbatim, so embedded `\n` can create additional log lines.

### Fix Focus Areas
- internal/cli/postrun_precommit.go[159-162]
- internal/cli/postrun_precommit.go[329-337]
- internal/ui/ui.go[76-82]
- internal/runtime/sanitize.go[11-28]
- docs/guides/user/customizing-agents.md[263-266]

### Implementation notes
- Add a small sanitizer for runner-log output and apply it to every warning string before `StepWarn` (and optionally `StepInfo` when the message includes untrusted data).
- Reuse the same transformations as `internal/runtime/sanitize.go` (replace `::`, strip `%0A/%0D` encodings, and replace control characters/newlines with spaces) or refactor that sanitizer into a shared/exported helper.
- Ensure sanitized warnings are single-line to prevent accidental emission of workflow command markers on subsequent lines.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread internal/cli/postrun_fixsummary.go Outdated
Comment thread internal/cli/postrun_precommit.go Outdated
Comment thread internal/cli/postrun_precommit.go Outdated
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review — approve

This PR fixes companion-script resolution in the four harness scripts (pre-code.sh, pre-fix.sh, post-code.sh, post-fix.sh) by adding a workspace-directory fallback when the BASH_SOURCE-relative lookup fails (#3069), and emitting ::warning:: annotations when companions are missing everywhere (#3070).

Implementation pivot

The prior review (SHA cd9ff41) evaluated a Go CLI subcommand approach (fullsend postrun precommit-install and fullsend postrun fix-summary). This revision replaces that approach entirely with a shell-only workspace fallback, per review feedback. The new approach is simpler: it leverages the fact that the reusable workflows' "Prepare workspace" step already materializes the full scripts/ directory (with L1 org overrides) at ${GITHUB_WORKSPACE}/scripts/ (per-org) or ${GITHUB_WORKSPACE}/.fullsend/scripts/ (per-repo). No new CLI surface, no Go changes, no release sequencing dependency.

Assessment

The change is safe and well-scoped:

  • Root cause correctly addressed. When the harness fetches scripts as single flat files into the content-addressed cache (fetchBaseFile in compose.go), companions aren't co-located. The fallback probes the two known workspace paths where companions are always available, restoring the auto-install without requiring changes to the harness compose system.
  • Fallback correctness verified. The fallback checks that both companion files exist at the candidate path before reassigning either variable, preventing partial-update states. When GITHUB_WORKSPACE is unset, ${GITHUB_WORKSPACE:-} produces an empty string, making candidates /scripts and /.fullsend/scripts — both non-existent on any runner, so the fallback is a safe no-op.
  • Warning pattern consistent with existing scripts. The post-* scripts check .pre-commit-config.yaml (cwd-relative, since they've already cd'd into the repo), while pre-* scripts check ${TARGET_REPO}/.pre-commit-config.yaml — matching the existing guard pattern in each file. The process-fix-result.py fallback in post-fix.sh correctly omits a separate warning block because the existing downstream code (line 337) already emits ::warning::process-fix-result.py not found at ${PROCESS_SCRIPT} — skipping.
  • GITHUB_WORKSPACE vs FULLSEND_DIR. The PR correctly uses GITHUB_WORKSPACE (absolute path, always available in childScriptEnv) instead of FULLSEND_DIR (which is the relative .fullsend for per-repo installs and would mis-resolve from the post-script's runDir cwd). This is a valid correction to the approach suggested in issue Post-script companion scripts not accessible when resolved from URL-based cache #3069.
  • No security regressions. The ::warning:: messages interpolate ${RESOLVE_SCRIPT} and ${INSTALL_SCRIPT}, both derived from BASH_SOURCE (runner filesystem path) or GITHUB_WORKSPACE (set by the GitHub Actions runner binary). Neither is user-controllable through normal GitHub Actions mechanisms. No path traversal risk, no prompt injection patterns, no Unicode steganography detected.
  • No test regressions. No test files were modified. The PR body confirms bash -n, shellcheck, and existing test suites pass.
  • Commit message correct. fix(#3069) prefix is appropriate per COMMITS.md — this is a user-visible bug fix (pre-commit tools silently failing). DCO sign-off present for human contributor. No breaking change, so no ! needed.

Low-severity observations (non-blocking)

  1. Code duplication across four scripts. The fallback + warning blocks are near-identical (~20 lines each) across all four scripts. The existing scripts already exhibit this pattern (pre-commit install logic, pre-commit hooks check, signing verification are all duplicated). Extracting to a shared helper would ironically create another companion file with the same resolution problem this PR fixes. Worth considering if the scripts are ever refactored to a shared sourced library, but not blocking.

  2. _ws_candidate naming convention. The loop variable uses an underscore prefix. Most loop variables in these scripts use unprefixed names (for label in, for file in, for dir in), but underscore-prefixed names are used for temporary/intermediate variables (_BASE_BR in pre-fix.sh:120, _TOKEN in pre-review.sh:57). _ws_candidate is a borderline case — it's a loop variable serving as a temporary. Consistent with the temporary-variable convention but not the loop-variable convention.

Verdict

Approve. The shell-only fallback is simpler than the prior Go CLI approach, introduces no new dependencies or release sequencing concerns, and correctly fixes the root cause. The low-severity observations are non-blocking style concerns suitable for a future refactoring pass.


Reviewed by fullsend review agent · fullsend-ai/fullsend

Previous run

Review — approve

This PR ports three Python/shell companion scripts (resolve-precommit-tools.py, install-precommit-tools.sh, process-fix-result.py) into Go CLI subcommands (fullsend postrun precommit-install and fullsend postrun fix-summary), eliminating the sibling-file dependency that broke when scripts were fetched from URL-based cache (#3069, #3070).

Changes since prior review

The fixup commit (cd9ff41) addressed several observations from the prior review:

  • Validation defense-in-depth added: validateFixResult() now checks structural invariants (non-empty actions, recognized action types, required companion fields) as a lightweight second check after the harness's upstream JSON Schema validation — closing the defense-in-depth gap noted in the prior review.
  • Dead code removed: skipTargetRepo declaration and its suppressor _ = skipTargetRepo are gone.
  • Forge interface at the right layer: postFixSummary() now accepts forge.Client interface rather than receiving a raw token and constructing the client internally. The concrete gh.New(token) instantiation remains at the command-factory level, consistent with every other CLI command.
  • GH_TOKEN fallback added: Token resolution now checks --tokenGITHUB_TOKENGH_TOKEN, with corresponding test coverage.
  • GHA annotation sanitization: All printer.StepWarn calls replaced with stepWarn(), which emits sanitized ::warning:: annotations when running under GitHub Actions. The sanitization regex strips :: sequences and URL-encoded newlines (%0A/%0D).

Assessment

The change is well-crafted and safe to merge:

  • Root cause addressed correctly. Moving companion script logic into the fullsend binary eliminates the sibling-file resolution problem entirely — fullsend is already present on the runner, so no fetch/co-location mechanism is needed.
  • Behavioral parity verified. The Go implementations of mergeRegistries, resolveTools, buildFixSummaryBody, and the binary/apt/pip/npm install dispatchers faithfully reproduce the logic of the deleted Python and shell scripts, including edge cases (deduplication, match_entry collision warnings, exclude support with correct match_entry ownership cleanup, architecture detection, checksum verification, comment truncation, exit code semantics).
  • Comprehensive test coverage. 968 lines of precommit tests and 263 lines of fix-summary tests cover registry merge/resolve logic (ported from the Python test suite), checksum-verified binary installs (via httptest), markdown summary rendering, validation edge cases, token fallback, forge client injection, and GHA annotation sanitization.
  • Shell script updates are consistent. All four modified scripts (post-code.sh, post-fix.sh, pre-code.sh, pre-fix.sh) follow the same pattern: replace the SCRIPT_DIR/RESOLVE_SCRIPT/INSTALL_SCRIPT file-existence guards with direct fullsend postrun precommit-install invocations. The post-fix.sh fix-summary invocation correctly preserves the gitleaks pre-scan and the exit-code-2 non-fatal semantics.
  • Clean removal. Deleted scripts are consistently removed from scaffold.go executableFiles, Makefile script-test, and .pre-commit-tools.yaml comments. No stale references remain in documentation or workflow files.

Low-severity observations (non-blocking)

  1. GHA sanitization gap: stepWarn's regex ((?i)::|%0[ad]) handles the primary GHA command injection vectors (:: markers and URL-encoded newlines) but omits ANSI escape stripping and control character filtering that the established sanitizeOutput() in internal/runtime/sanitize.go provides. No regression from the deleted shell scripts (which used the same level of sanitization), but reusing or aligning with sanitizeOutput() would be a defense-in-depth improvement. The data flowing through stepWarn comes from base-branch .pre-commit-config.yaml (semi-trusted), so the practical risk is log-spoofing rather than command injection.

  2. Tar extraction path validation: extractTarGz delegates to system tar without path sanitization — same gap as the deleted bash script. The checksum verification and registry trust model (URLs from base-branch-only registries per ADR 0056) make this a defense-in-depth concern rather than an exploitable vulnerability. Switching to Go's archive/tar with ../ and absolute-path rejection would be a worthwhile follow-up.

  3. CLI docs gap: docs/guides/dev/cli-internals.md has a command tree (lines 8–86) that does not include the new fullsend postrun subcommands. Worth updating in a follow-up commit.

Verdict

Approve. The fixup commit strengthened the code across multiple dimensions (validation, forge interface, token fallback, GHA sanitization). The remaining observations are non-blocking, defense-in-depth improvements suitable for follow-up work.


Reviewed by fullsend review agent · fullsend-ai/fullsend

Previous run

Review — approve

This PR ports three Python/shell companion scripts (resolve-precommit-tools.py, install-precommit-tools.sh, process-fix-result.py) into Go CLI subcommands (fullsend postrun precommit-install and fullsend postrun fix-summary), eliminating the sibling-file dependency that broke when scripts were fetched from URL-based cache (#3069, #3070).

Assessment

The change is well-crafted and safe to merge:

  • Root cause addressed correctly. Moving companion script logic into the fullsend binary eliminates the sibling-file resolution problem entirely — fullsend is already present on the runner, so no fetch/co-location mechanism is needed.
  • Behavioral parity verified. The Go implementations of mergeRegistries, resolveTools, buildFixSummaryBody, and the binary/apt/pip/npm install dispatchers faithfully reproduce the logic of the deleted Python and shell scripts, including edge cases (deduplication, match_entry collision warnings, exclude support, architecture detection, checksum verification, comment truncation, exit code semantics).
  • Comprehensive test coverage. The new test files (941 lines for precommit, 144 lines for fix-summary) port the original Python test suites and add Go-specific tests including httptest-based binary install end-to-end tests, checksum mismatch verification, architecture override validation, and registry merge edge cases.
  • Shell script updates are consistent. All four modified scripts (post-code.sh, post-fix.sh, pre-code.sh, pre-fix.sh) follow the same pattern: replace the SCRIPT_DIR/RESOLVE_SCRIPT/INSTALL_SCRIPT file-existence guards with direct fullsend postrun precommit-install invocations. The post-fix.sh fix-summary invocation correctly preserves the gitleaks pre-scan and the exit-code-2 non-fatal semantics.
  • Clean removal. Deleted scripts are consistently removed from scaffold.go executableFiles, Makefile script-test, and .pre-commit-tools.yaml comments.
  • No stale references. Grep confirms no documentation files reference the deleted script names.

Notes

  • Forge client pattern: postrun_fixsummary.go uses gh.New(token) directly rather than the forge.Client interface. This follows the established pattern in every other CLI command (postcomment.go, postreview.go, reconcilestatus.go, admin.go, etc. — 13+ files), so it is consistent with the codebase even though AGENTS.md aspires to full interface abstraction.
  • Schema validation omitted intentionally: The Python process-fix-result.py validated fix-result.json against its JSON schema; the Go port skips this with a documented rationale that the harness validation_loop already validates before post-fix.sh runs. This is a reasonable design choice that removes redundancy while slightly reducing defense-in-depth for ad-hoc invocations.
  • Dead code: skipTargetRepo in newPostrunPrecommitInstallCmd() is declared but immediately suppressed with _ = skipTargetRepo. Appears to be a leftover from an earlier iteration — safe to remove.
  • Tar extraction path validation: extractTarGz delegates to system tar without path sanitization (same as the deleted bash script). The checksum verification and registry trust model (URLs come from base-branch-only registries) make this a defense-in-depth concern rather than an exploitable vulnerability, but switching to Go's archive/tar with path validation would be a worthwhile follow-up improvement.

Verdict

Approve. The PR fixes a real, high-priority bug with a clean architectural approach, comprehensive tests, and faithful behavioral parity. The notes above are non-blocking observations for future improvement.


Reviewed by fullsend review agent · fullsend-ai/fullsend


Labels: PR adds new CLI commands under internal/cli/ and modifies harness post-scripts under internal/scaffold/

Previous run

Review — approve

This PR ports three Python/shell companion scripts (resolve-precommit-tools.py, install-precommit-tools.sh, process-fix-result.py) into Go CLI subcommands (fullsend postrun precommit-install and fullsend postrun fix-summary), eliminating the sibling-file dependency that broke when scripts were fetched from URL-based cache (#3069, #3070).

Changes since prior review

The fixup commit (cd9ff41) addressed several observations from the prior review:

  • Validation defense-in-depth added: validateFixResult() now checks structural invariants (non-empty actions, recognized action types, required companion fields) as a lightweight second check after the harness's upstream JSON Schema validation — closing the defense-in-depth gap noted in the prior review.
  • Dead code removed: skipTargetRepo declaration and its suppressor _ = skipTargetRepo are gone.
  • Forge interface at the right layer: postFixSummary() now accepts forge.Client interface rather than receiving a raw token and constructing the client internally. The concrete gh.New(token) instantiation remains at the command-factory level, consistent with every other CLI command.
  • GH_TOKEN fallback added: Token resolution now checks --tokenGITHUB_TOKENGH_TOKEN, with corresponding test coverage.
  • GHA annotation sanitization: All printer.StepWarn calls replaced with stepWarn(), which emits sanitized ::warning:: annotations when running under GitHub Actions. The sanitization regex strips :: sequences and URL-encoded newlines (%0A/%0D).

Assessment

The change is well-crafted and safe to merge:

  • Root cause addressed correctly. Moving companion script logic into the fullsend binary eliminates the sibling-file resolution problem entirely — fullsend is already present on the runner, so no fetch/co-location mechanism is needed.
  • Behavioral parity verified. The Go implementations of mergeRegistries, resolveTools, buildFixSummaryBody, and the binary/apt/pip/npm install dispatchers faithfully reproduce the logic of the deleted Python and shell scripts, including edge cases (deduplication, match_entry collision warnings, exclude support with correct match_entry ownership cleanup, architecture detection, checksum verification, comment truncation, exit code semantics).
  • Comprehensive test coverage. 968 lines of precommit tests and 263 lines of fix-summary tests cover registry merge/resolve logic (ported from the Python test suite), checksum-verified binary installs (via httptest), markdown summary rendering, validation edge cases, token fallback, forge client injection, and GHA annotation sanitization.
  • Shell script updates are consistent. All four modified scripts (post-code.sh, post-fix.sh, pre-code.sh, pre-fix.sh) follow the same pattern: replace the SCRIPT_DIR/RESOLVE_SCRIPT/INSTALL_SCRIPT file-existence guards with direct fullsend postrun precommit-install invocations. The post-fix.sh fix-summary invocation correctly preserves the gitleaks pre-scan and the exit-code-2 non-fatal semantics.
  • Clean removal. Deleted scripts are consistently removed from scaffold.go executableFiles, Makefile script-test, and .pre-commit-tools.yaml comments. No stale references remain in documentation or workflow files.

Low-severity observations (non-blocking)

  1. GHA sanitization gap: stepWarn's regex ((?i)::|%0[ad]) handles the primary GHA command injection vectors (:: markers and URL-encoded newlines) but omits ANSI escape stripping and control character filtering that the established sanitizeOutput() in internal/runtime/sanitize.go provides. No regression from the deleted shell scripts (which used the same level of sanitization), but reusing or aligning with sanitizeOutput() would be a defense-in-depth improvement. The data flowing through stepWarn comes from base-branch .pre-commit-config.yaml (semi-trusted), so the practical risk is log-spoofing rather than command injection.

  2. Tar extraction path validation: extractTarGz delegates to system tar without path sanitization — same gap as the deleted bash script. The checksum verification and registry trust model (URLs from base-branch-only registries per ADR 0056) make this a defense-in-depth concern rather than an exploitable vulnerability. Switching to Go's archive/tar with ../ and absolute-path rejection would be a worthwhile follow-up.

  3. CLI docs gap: docs/guides/dev/cli-internals.md has a command tree (lines 8–86) that does not include the new fullsend postrun subcommands. Worth updating in a follow-up commit.

Verdict

Approve. The fixup commit strengthened the code across multiple dimensions (validation, forge interface, token fallback, GHA sanitization). The remaining observations are non-blocking, defense-in-depth improvements suitable for follow-up work.


Reviewed by fullsend review agent · fullsend-ai/fullsend

Previous run (2)

Review — approve

This PR ports three Python/shell companion scripts (resolve-precommit-tools.py, install-precommit-tools.sh, process-fix-result.py) into Go CLI subcommands (fullsend postrun precommit-install and fullsend postrun fix-summary), eliminating the sibling-file dependency that broke when scripts were fetched from URL-based cache (#3069, #3070).

Assessment

The change is well-crafted and safe to merge:

  • Root cause addressed correctly. Moving companion script logic into the fullsend binary eliminates the sibling-file resolution problem entirely — fullsend is already present on the runner, so no fetch/co-location mechanism is needed.
  • Behavioral parity verified. The Go implementations of mergeRegistries, resolveTools, buildFixSummaryBody, and the binary/apt/pip/npm install dispatchers faithfully reproduce the logic of the deleted Python and shell scripts, including edge cases (deduplication, match_entry collision warnings, exclude support, architecture detection, checksum verification, comment truncation, exit code semantics).
  • Comprehensive test coverage. The new test files (941 lines for precommit, 144 lines for fix-summary) port the original Python test suites and add Go-specific tests including httptest-based binary install end-to-end tests, checksum mismatch verification, architecture override validation, and registry merge edge cases.
  • Shell script updates are consistent. All four modified scripts (post-code.sh, post-fix.sh, pre-code.sh, pre-fix.sh) follow the same pattern: replace the SCRIPT_DIR/RESOLVE_SCRIPT/INSTALL_SCRIPT file-existence guards with direct fullsend postrun precommit-install invocations. The post-fix.sh fix-summary invocation correctly preserves the gitleaks pre-scan and the exit-code-2 non-fatal semantics.
  • Clean removal. Deleted scripts are consistently removed from scaffold.go executableFiles, Makefile script-test, and .pre-commit-tools.yaml comments.
  • No stale references. Grep confirms no documentation files reference the deleted script names.

Notes

  • Forge client pattern: postrun_fixsummary.go uses gh.New(token) directly rather than the forge.Client interface. This follows the established pattern in every other CLI command (postcomment.go, postreview.go, reconcilestatus.go, admin.go, etc. — 13+ files), so it is consistent with the codebase even though AGENTS.md aspires to full interface abstraction.
  • Schema validation omitted intentionally: The Python process-fix-result.py validated fix-result.json against its JSON schema; the Go port skips this with a documented rationale that the harness validation_loop already validates before post-fix.sh runs. This is a reasonable design choice that removes redundancy while slightly reducing defense-in-depth for ad-hoc invocations.
  • Dead code: skipTargetRepo in newPostrunPrecommitInstallCmd() is declared but immediately suppressed with _ = skipTargetRepo. Appears to be a leftover from an earlier iteration — safe to remove.
  • Tar extraction path validation: extractTarGz delegates to system tar without path sanitization (same as the deleted bash script). The checksum verification and registry trust model (URLs come from base-branch-only registries) make this a defense-in-depth concern rather than an exploitable vulnerability, but switching to Go's archive/tar with path validation would be a worthwhile follow-up improvement.

Verdict

Approve. The PR fixes a real, high-priority bug with a clean architectural approach, comprehensive tests, and faithful behavioral parity. The notes above are non-blocking observations for future improvement.


Reviewed by fullsend review agent · fullsend-ai/fullsend


Labels: PR adds new CLI commands under internal/cli/ and modifies harness post-scripts under internal/scaffold/

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge component/harness Agent harness, config, and skills loading labels Jul 7, 2026
@ifireball

Copy link
Copy Markdown
Member

@waynesun09 I'm not sure I am on-page with the approach of converting all the sibling scripts into fullsend CLI sub-commands. It might make sense for a limited set of things but not across the board. We should have probably taken #3182 as a warning that we've taken a bad turn.

I think we should try packaging the sets of scripts as dummy skills. That can probably work now. The only issue I see with it is that we then end up with the scripts inside the sandbox. I think we can live with that for now. The next step will be to probably allow applying the same directory fetching logic we have for skill for per/post scripts as well.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:30 PM UTC · Completed 6:41 PM UTC
Commit: cd9ff41 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed ready-for-merge All reviewers approved — ready to merge labels Jul 7, 2026
@waynesun09

Copy link
Copy Markdown
Member Author

@ifireball you're right, and digging into it further changed my mind on the approach entirely — not just the "single-use vs shared" split I was originally going to propose.

Where this actually breaks: post-code.sh has two independent sections — section 4 resolves the registry and installs tools (lychee, actionlint, etc.) onto PATH; section 5 just runs pre-commit run. Section 5 never changes and doesn't care how tools got installed — it only broke because section 4's SCRIPT_DIR_POST=$(dirname "${BASH_SOURCE[0]}") guess is wrong once post-code.sh itself is fetched as a lone blob, so the guard silently skips the whole install step.

Why a CLI subcommand is the wrong fix: the reusable workflow (reusable-code.yml) lives in fullsend-ai/fullsend, and its "Checkout upstream defaults" step sparse-checks out fullsend-ai/fullsend itself (via job.workflow_repository/job.workflow_sha) — pulling internal/scaffold/fullsend-repo/scripts/ (with L1 org overrides applied by "Prepare workspace") onto disk at ${GITHUB_WORKSPACE}/scripts/ or .../.fullsend/scripts/, on every job, unconditionally, regardless of where post-code.sh itself was resolved from. resolve-precommit-tools.py / install-precommit-tools.sh / .pre-commit-tools.yaml / process-fix-result.py were never really "sibling files of an agent script" — they're fullsend-repo scaffold assets that are always present at a known workspace path. The only thing broken is that post-code.sh/post-fix.sh (which did move to fullsend-ai/agents) lost track of where that always-present copy landed, because they were guessing from their own BASH_SOURCE.

So the real fix is much smaller than what I originally posted: add a fallback in pre-code.sh/post-code.sh/pre-fix.sh/post-fix.sh — if the companion isn't found next to BASH_SOURCE, fall back to ${GITHUB_WORKSPACE}[/.fullsend]/scripts/, which "Prepare workspace" always populates. This is exactly what the triage agent recommended in #3069's Option A. No new CLI surface, no Go port, no new binary to test/maintain — I'm reworking the PR to that shape and will drop the fullsend postrun command entirely. This also removes the sequencing dependency on the companion fullsend-ai/agents PR waiting for a fullsend release, since there's no new subcommand to ship first.

Thanks for pushing on this — will update shortly.

@ralphbean ralphbean left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. One note inline.

precommit-install is solid agent-agnostic infrastructure. fix-summary is more coupled to fix-result.json's schema though — action types, decision points, the full rendering. If we're keeping third-party agents decoupled from the core binary, could the fix agent render its own markdown and a generic "post comment from file" subcommand handle the rest?

Comment thread internal/cli/postrun_fixsummary.go Outdated
if len(body) > maxFixSummaryCommentLength {
truncationNotice := "\n\n*[truncated — output exceeded 32KB]*"
stepWarn(printer, fmt.Sprintf("comment body truncated from %d to %d chars", len(body), maxFixSummaryCommentLength))
body = body[:maxFixSummaryCommentLength-len(truncationNotice)] + truncationNotice

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[minor] body[:maxFixSummaryCommentLength-len(truncationNotice)] slices by byte offset — could split a multi-byte UTF-8 character if the cut lands mid-codepoint (the header's wrench emoji alone is 4 bytes). Non-blocking, but walking backward to a rune boundary would be cleaner.

pre-code.sh, pre-fix.sh, post-code.sh, and post-fix.sh locate their
companion files (resolve-precommit-tools.py, install-precommit-tools.sh,
process-fix-result.py) next to BASH_SOURCE. That breaks when the script
itself is resolved from a URL base: the harness fetches scripts as
single flat files into the content-addressed cache with no siblings, so
the lookups silently miss and pre-commit tool auto-install (and the
fix-agent summary comment) are skipped.

The companions never needed to travel with the script: the reusable
workflows' "Prepare workspace" step always materializes the full
scripts/ directory (with L1 org overrides applied) at
GITHUB_WORKSPACE/scripts (per-org) or GITHUB_WORKSPACE/.fullsend/scripts
(per-repo). Fall back to those absolute paths when the
BASH_SOURCE-relative lookup misses. GITHUB_WORKSPACE is used instead of
FULLSEND_DIR because post-scripts run with cwd=runDir, where the
per-repo relative FULLSEND_DIR value would mis-resolve.

Executing the workspace copy also means resolve-precommit-tools.py
finds the L1-overridden .pre-commit-tools.yaml next to itself, so org
registry overrides keep working.

Also warn instead of silently skipping when the companions are missing
everywhere (#3070), so the failure no longer surfaces only as a
confusing "Executable X not found" at the pre-commit gate.

Fixes #3069
Fixes #3070

Assisted-by: Claude (fix and verification)
Signed-off-by: Wayne Sun <gsun@redhat.com>
@waynesun09 waynesun09 changed the title feat(cli): add postrun command for pre-commit tools and fix summaries fix(#3069): fall back to workspace scripts dir for script companions Jul 7, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Review · ❌ Terminated · Started 8:25 PM UTC · Ended 8:37 PM UTC
Commit: e8381e3 · View workflow run →

@waynesun09

Copy link
Copy Markdown
Member Author

Rework pushed — the PR is now the minimal workspace-fallback fix described above: +114/−1 across the four scaffold scripts, no Go changes, fullsend postrun dropped entirely. Title and description updated to match.

Two notes from re-verifying against #3069's triage:

  • Used ${GITHUB_WORKSPACE} instead of the triage's suggested ${FULLSEND_DIR}: post-scripts run with cwd=runDir, where the per-repo FULLSEND_DIR value (relative .fullsend) would mis-resolve. GITHUB_WORKSPACE is absolute and already in the post-script env via childScriptEnv, so no harness YAML plumbing is needed.
  • Also added the missing-companion ::warning:: from Post-script pre-commit tool auto-install should warn when companion scripts are not found #3070, since the silent skip was what made the original failure so hard to diagnose.

@ralphbean your two comments on the Go files (sanitizer reuse, byte-offset truncation) are moot now — those files no longer exist in this PR.

# at ${GITHUB_WORKSPACE}/scripts/ (per-org) or ${GITHUB_WORKSPACE}/.fullsend/scripts/
# (per-repo). Try those paths when the BASH_SOURCE-relative lookup misses.
if [ ! -f "${RESOLVE_SCRIPT}" ] || [ ! -f "${INSTALL_SCRIPT}" ]; then
for _ws_candidate in "${GITHUB_WORKSPACE:-}/scripts" "${GITHUB_WORKSPACE:-}/.fullsend/scripts"; do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] naming-convention

Loop variable _ws_candidate uses underscore prefix, which matches the codebase convention for temporary variables (_BASE_BR, _TOKEN) but not the convention for loop variables (label, file, dir). Borderline — consistent with one convention, inconsistent with another.

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed ready-for-merge All reviewers approved — ready to merge labels Jul 7, 2026
@fullsend-ai-review

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:25 PM UTC · Completed 8:37 PM UTC
Commit: fa96e95 · View workflow run →

@waynesun09 waynesun09 added this pull request to the merge queue Jul 7, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 7, 2026
@waynesun09 waynesun09 added this pull request to the merge queue Jul 8, 2026
Merged via the queue into main with commit 4180ae6 Jul 8, 2026
21 of 23 checks passed
@waynesun09 waynesun09 deleted the postrun-command branch July 8, 2026 14:16
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 2:18 PM UTC · Completed 2:27 PM UTC
Commit: fa96e95 · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

PR #3393 fixed companion-script resolution for pre/post-code/fix scripts by adding a workspace-directory fallback when BASH_SOURCE-relative lookups fail. The workflow involved a significant approach pivot: the initial submission was a Go CLI subcommand approach (fullsend postrun) that the review agent approved twice, but a human reviewer correctly identified it as over-engineered. The author agreed and reworked to a minimal shell-only fallback (+114/-1, no Go changes). Key observations: (1) the review agent approved an unnecessarily complex approach without flagging simpler alternatives, costing 2 wasted review runs; (2) this is the third instance of fetchBaseFile's single-file model breaking scripts with companion files (after #2705 and #3182); (3) the final fix duplicates the same ~20-line fallback block across 4 scripts. Two proposals filed: one for the review agent's approach-evaluation gap, one for the systemic script-resolution root cause.

Proposals filed

waynesun09 added a commit to fullsend-ai/agents that referenced this pull request Jul 8, 2026
fullsend-ai/fullsend#3393 dropped the `fullsend postrun` subcommand
approach (per review feedback there) in favor of a workspace-directory
fallback for companion-script lookup, so the previous commit on this
branch now calls subcommands that were never shipped and never will
be. Rework to mirror 3393's actual fix instead.

post-code.sh, post-fix.sh, pre-code.sh, pre-fix.sh: after the
BASH_SOURCE-relative lookup for resolve-precommit-tools.py /
install-precommit-tools.sh / process-fix-result.py misses (it always
does here, since those companions were never migrated into this repo
during the ADR 0058 extraction), fall back to ${GITHUB_WORKSPACE}/scripts/
then ${GITHUB_WORKSPACE}/.fullsend/scripts/ — the path the reusable
workflow's "Prepare workspace" step materializes fullsend's own
scaffold scripts/ directory at on every job. Warn instead of silently
skipping when the companions are missing everywhere.

Fixes fullsend-ai/fullsend#3069
Fixes fullsend-ai/fullsend#3070

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/harness Agent harness, config, and skills loading ready-for-merge All reviewers approved — ready to merge

Projects

None yet

4 participants