nebari-dev / nebari-dev/nebari-frames

Inheritance resolution: merge parent and child content with child priority

Open
#62 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

needs: discussion 💬 type: enhancement 💅🏼
Dominant language
Go
Stars
2
Forks
1
Avg merge
10h 55m
Merged PRs (30d)
9

Description

Motivation

Inheritance is the core promise of Frames: a team Frame extends an org Frame and refines it. The resolver in backend/internal/frames/resolver.go currently walks the extends graph, honors excludes, detects cycles, dedupes diamonds - and then merges by concatenating bodies, ancestors first and the child's body last.

Concatenation is only a proxy for merging. The resolved Frame reads as a pile of documents rather than one document: a parent's rule and a child's contradicting rule both survive, and the reader (a model) has to infer that the later one wins from ordering alone. As inheritance chains get deeper, resolved output gets longer and more self-contradictory - the opposite of what a Frame is for.

Proposal

Make resolution a real merge where the child has priority and parent content is carried forward rather than duplicated:

  • Merge on structure within the body rather than treating it as an opaque blob: content under the same heading merges, with the child's version taking precedence; content only the parent has is inherited; content only the child has is added.
  • Child content overrides the corresponding parent content instead of appending after it. Where a genuine conflict cannot be resolved structurally, the child wins.
  • Preserve the existing guarantees: excludes still prunes ancestors, diamonds still contribute once, cycles still error, unreadable ancestors still fail closed.
  • Keep the resolved output attributable enough to debug - an author looking at a resolved Frame should be able to tell which ancestor a piece of content came from (the web app's hierarchy view and ResolvedPreview are the consumers here).

Open questions

  • What is the merge key? Markdown headings are the obvious candidate, but that makes heading text load-bearing and needs a defined answer for un-headed prose and for a child that renames a parent's heading.
  • Should a child be able to explicitly remove an inherited section, as opposed to overriding it? excludes prunes whole ancestors, not parts.

Acceptance criteria

  • Overlapping content between a child and its ancestors resolves to the child's version, not both.
  • Non-overlapping ancestor content is still inherited.
  • Deep chains and diamonds resolve without duplicated content.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in backend/internal/frames/resolver.go and trace how resolved content reaches the web app's hierarchy view and ResolvedPreview. Define the merge behavior for headings, unheaded prose, renamed sections, removals, attribution, and unresolved conflicts before changing resolution. Done means child content wins, unique parent content remains, deep chains and diamonds avoid duplication, and existing excludes, cycle, and unreadable-ancestor behavior is preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.