fix(#6798): preserve child top-level fields over inherited forge values - #6801
fix(#6798): preserve child top-level fields over inherited forge values#6801fullsend-ai-coder[bot] wants to merge 3 commits into
Conversation
When a child harness extends a base via `base:` and sets top-level fields (pre_script, post_script, policy, skills, providers, env, etc.), those values were silently overridden by forge-level values inherited from the base during ResolveForge. mergeForgeBlocks inherited the entire base ForgeConfig wholesale for platforms the child didn't define, and mergeForgeConfig could not distinguish between forge values the child explicitly set and values inherited from the base. Fix: snapshot the child's explicit top-level fields and forge platform keys at the start of mergeBaseIntoChild, before any merging. After mergeForgeBlocks, clear inherited forge-level fields that would override the child's explicit top-level values: - Scalars (PreScript, PostScript, Policy): cleared on inherited platforms when the child set the corresponding top-level value - Slices (Skills, Providers, OpenShell.Profiles, HostFiles): cleared when the child defined its own top-level entries - Maps (RunnerEnv, Env): only matching keys removed, preserving forge-only keys the child did not set Note: pre-commit hooks could not run in sandbox (network blocked for git fetch). gofmt and go vet passed via direct execution. Closes #6798
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
🤖 Finished Review · ✅ Success · Started 2:28 PM UTC · Completed 3:04 PM UTC Commit: Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $5.46 |
|
Risk Assessment: elevated (3/5) DetailsElevated risk driven by Tier 2: compose.go remains a high-churn hotspot (54 commits, 7 authors, 32 fix/revert commits in 6 months). Tier 1 signals are effectively unchanged from prior assessment (4 files, 359 lines, medium blast radius). Tier 3 remains low — well-scoped priority/high bug fix with all acceptance criteria met. Score anchored at prior value of 3 as no signals shifted materially. Previous runRisk Assessment: elevated (3/5) DetailsElevated risk driven by Tier 2: compose.go is a high-churn hotspot (62 commits, 7 authors, 10+ fix commits in 6 months) in a large, complex module under active evolution. The PR itself is well-scoped (2 files, 50% test ratio, priority/high bug fix with all acceptance criteria met), keeping Tier 1 and Tier 3 moderate-to-low. |
ReviewFindingsLow
Next steps:
Previous runReviewFindingsMedium
Low
Next steps:
|
|
🤖 Finished Fix · ✅ Success · Started 3:06 PM UTC · Completed 3:14 PM UTC Commit: Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $2.16 |
- Add missing ValidationLoop to the inherited forge-level clearing loop in mergeBaseIntoChild, preventing the same silent-override bug that the PR fixes for other fields (missing-field finding) - Rename subtests in TestLoadWithBase_ChildTopLevelOverridesInheritedForge from snake_case to space-separated lower-case to match existing compose_test.go conventions (naming-convention finding) - Add a new "validation loop" subtest covering the ValidationLoop fix - Update docs/contributing/harness-fields.md to note the post-merge clearing step specific to base composition (stale-behavior finding) - Update docs/contributing/harness-composition.md to document the post-merge clearing step after mergeForgeBlocks (stale-behavior finding) Addresses review feedback on #6801
🔧 Fix agent — iteration 1 (bot-triggered)Addressed all 4 review findings. Added missing ValidationLoop handling to the forge-level clearing loop with a new test. Renamed subtests to match repo conventions. Updated both harness-fields.md and harness-composition.md to document the post-merge clearing step. Fixed (4):
Tests: passedNext steps:
|
Site previewPreview: https://f5df2090-site.fullsend-ai.workers.dev Commit: |
|
🤖 Finished Review · ✅ Success · Started 3:17 PM UTC · Completed 3:34 PM UTC Commit: Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $5.49 |
| @@ -544,6 +544,43 @@ func matchingAllowedPrefix(rawURL string, allowlist []string) string { | |||
| // - forge: key-by-key merge; per-platform uses same rules | |||
There was a problem hiding this comment.
[low] documentation-comment
The mergeBaseIntoChild doc comment enumerates all merge rules as a bulleted list but does not mention the new post-merge clearing step for inherited forge-level fields. The existing bullet 'forge: key-by-key merge; per-platform uses same rules' is now incomplete — after mergeForgeBlocks, inherited forge platforms have conflicting fields cleared. The contributing docs (harness-composition.md, harness-fields.md) were updated, but the function's own doc comment was not.
Suggested fix: Extend the forge bullet or add a new bullet, e.g., 'forge: key-by-key merge; per-platform uses same rules; inherited platforms have fields cleared where child set explicit top-level values (#6798)'.
|
🤖 Finished Fix · ✅ Success · Started 3:36 PM UTC · Completed 3:41 PM UTC Commit: Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $0.94 |
🔧 Fix agent — iteration 2 (bot-triggered)Addressed 1 review finding. Updated the mergeBaseIntoChild function doc comment to document the post-merge clearing step for inherited forge-level fields. Fixed (1):
Tests: passedNext steps:
|
Summary
pre_script,post_script,policy,skills,providers,runner_env,env) by inherited forge-level values from base harnessesmergeBaseIntoChild, snapshot the child's explicit top-level fields and forge platform keys before merge, then clear inherited forge-level fields that would collide with the child's explicit intentTesting
TestLoadWithBase_ChildTopLevelOverridesInheritedForgewith 6 subtests covering:go test ./internal/harness/...passesmergeBaseIntoChild: 95.5%Closes #6798
Post-script verification
agent/6798-fix-forge-inherit-override)92c1d6498c16ee9fa490150a6405c1bb974aff4a..HEAD)