PRD: Multi-parent extends: for bottles #272

Merged
didericis merged 4 commits from multi-parent-extends into main 2026-06-25 07:39:55 -04:00
Collaborator

Closes #268.

PRD

Summary

  • extends: now accepts a list of bottle names in addition to a plain string
  • Parents are resolved independently and folded left-to-right into a combined parent before the child merge
  • All existing single-parent behavior is unchanged (backward compatible)

Merge rules

For the left-to-right parent fold, later beats earlier on conflict:

Field Rule
env dict merge, later wins on collision
git-gate.user per-field overlay, later wins on non-empty
git-gate.repos union by name; same-name entries merged per-field, later wins
egress.routes concatenate (earlier first)
egress.log, supervise, agent_provider last-wins

Child-wins-over-all-parents is unchanged from PRD 0025.

Schema

# single parent — unchanged
extends: base

# multiple parents — new
extends: [base, networking]
Closes #268. [PRD](https://gitea.dideric.is/didericis/bot-bottle/src/commit/b8e2ce0b4d5f5cfc5103c178f0997a1e587c354e/docs/prds/prd-new-multi-parent-extends.md) ## Summary - `extends:` now accepts a list of bottle names in addition to a plain string - Parents are resolved independently and folded left-to-right into a combined parent before the child merge - All existing single-parent behavior is unchanged (backward compatible) ## Merge rules For the left-to-right parent fold, later beats earlier on conflict: | Field | Rule | |---|---| | `env` | dict merge, later wins on collision | | `git-gate.user` | per-field overlay, later wins on non-empty | | `git-gate.repos` | union by name; same-name entries merged per-field, later wins | | `egress.routes` | concatenate (earlier first) | | `egress.log`, `supervise`, `agent_provider` | last-wins | Child-wins-over-all-parents is unchanged from PRD 0025. ## Schema ```yaml # single parent — unchanged extends: base # multiple parents — new extends: [base, networking] ```
didericis reviewed 2026-06-25 03:25:39 -04:00
@@ -62,0 +81,4 @@
f"defined. Available bottles: {avail}"
)
if len(parent_names) == 1:
Owner

Doesn't seem like there's a good reason to have a separate condition for 1 parent... why not just always call "fold_parents"?

Doesn't seem like there's a good reason to have a separate condition for 1 parent... why not just always call "fold_parents"?
didericis marked this conversation as resolved
didericis force-pushed multi-parent-extends from ea1f022f1a to bffd5043dc 2026-06-25 04:33:14 -04:00 Compare
didericis force-pushed multi-parent-extends from bffd5043dc to 36a512bb4a 2026-06-25 04:42:25 -04:00 Compare
didericis added 3 commits 2026-06-25 05:10:09 -04:00
Allow extends: to accept a list of bottle names in addition to a plain
string. Parents are resolved independently and folded left-to-right
into a single combined parent before the child is merged on top, so
orthogonal concerns (base env, networking, agent provider) can live in
separate bottles without forcing a linear chain.

Merge rules for the parent fold: env dict-merge with later winning on
collision; git-gate.user per-field overlay; git-gate.repos union by
name with later winning per-field on same name; egress.routes
concatenated; all scalar fields (supervise, agent_provider, egress.log)
use last-wins. The existing child-wins-over-all-parents rule is
unchanged. Cycle detection, diamond deduplication, and missing/invalid
parent errors all work across multi-parent graphs.

Closes #268
Validate list entries against object-typed raw_list before narrowing to
list[str], so the isinstance(pname, str) check is not redundant.
refactor: drop redundant single-parent fast path in _resolve_one_bottle
lint / lint (push) Failing after 1m50s
test / unit (pull_request) Successful in 36s
test / integration (pull_request) Successful in 18s
75755a472f
_fold_parents with one name returns after the first resolve; the
single-element branch was a verbatim copy of the general path.
didericis force-pushed multi-parent-extends from 36a512bb4a to 75755a472f 2026-06-25 05:10:09 -04:00 Compare
didericis-codex added 1 commit 2026-06-25 05:45:59 -04:00
fix: remove unused supervise import for pyright
test / unit (pull_request) Successful in 37s
test / integration (pull_request) Successful in 17s
lint / lint (push) Successful in 1m48s
Update Quality Badges / update-badges (push) Failing after 1m18s
prd-number / assign-numbers (push) Successful in 23s
test / unit (push) Successful in 33s
test / integration (push) Successful in 17s
90e84a52e6
didericis merged commit 90e84a52e6 into main 2026-06-25 07:39:55 -04:00
didericis deleted branch multi-parent-extends 2026-06-25 07:39:56 -04:00
Sign in to join this conversation.