Skip to content

Feat: Add composable Scene modifiers and Scene environment propagation - #70

Merged
phranck merged 3 commits into
mainfrom
issue/19-scene-composition
Jul 22, 2026
Merged

Feat: Add composable Scene modifiers and Scene environment propagation#70
phranck merged 3 commits into
mainfrom
issue/19-scene-composition

Conversation

@phranck

@phranck phranck commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Closes #19. Fixes #2.

Summary

  • Scene gets SwiftUI's protocol shape (associatedtype Body: Scene, @SceneBuilder var body) with Never as the primitive terminator; WindowGroup declares a primitive body and SceneBuilder gains buildExpression
  • New composable scene-modifier layer: Scene.environment(_:_:), .palette(_:), .appearance(_:) wrap scenes in an internal EnvironmentModifiedScene; SceneResolution unwinds chains outside-in into the frame environment (inner values win) and hands the renderable core to the render loop — this layer is the documented extension point for the Enhancement: Implementation of an Application Menu System #5 command infrastructure
  • RenderLoop applies scene values before the view-level root palette override, so scene environment reaches all child views and out-of-tree surfaces (status bar, app header); identity paths stay byte-identical for unwrapped scenes via existential opening
  • ScenePhase (background < inactive < active) with a scenePhase environment key defaulting to .active; phase-driven actions arrive with [P2-28] Add terminal accessibility, search, refresh, and application actions #33, multiwindow semantics deliberately not copied
  • The README/issue-#2 shape WindowGroup { … }.palette(…) now compiles and changes rendered colors; covered by tests and the scene compile fixture (including an App body using scene modifiers)

Test plan

  • 1372 tests green on macOS (Swift 6.0.3) and Linux (Docker 6.0.3-noble), warning-fatal, via ./scripts/test-linux.sh
  • New SceneCompositionTests: resolution, outside-in composition, innermost-wins, rendering through modifiers, ScenePhase defaults/ordering
  • verify-compatibility-manifest.sh passes against the regenerated manifest

phranck added 3 commits July 22, 2026 14:30
- Give Scene the SwiftUI protocol shape (associated Body, SceneBuilder
  body) with Never as the primitive terminator
- Add the EnvironmentModifiedScene layer with Scene.environment(_:_:),
  .palette(_:), and .appearance(_:) modifiers; SceneResolution unwinds
  modifier chains outside-in into the frame environment (inner values
  win) and returns the renderable core
- Resolve scenes in RenderLoop before the view-level root palette
  override so scene values reach all views and out-of-tree surfaces;
  identity paths stay byte-identical for unwrapped scenes
- Add ScenePhase with an environment key (active by default); phase
  actions arrive with the application-actions work
- Fixes the documented WindowGroup { … }.palette(…) shape from issue #2
- Add the scene-level palette section to the theming guide
- Extend the scene fixture with the issue-2 palette shape, composed
  modifiers, and an App body using scene modifiers
- Add overrides for the Scene protocol body contract, the scene
  environment modifiers, WindowGroup's primitive body, ScenePhase, and
  the scenePhase environment key
- Regenerate the manifest with TUIkitAPICheck against fresh 6.0.3
  macOS and Linux snapshots
@phranck
phranck merged commit 618039a into main Jul 22, 2026
6 checks passed
@phranck
phranck deleted the issue/19-scene-composition branch July 22, 2026 12:51
wadetregaskis added a commit to wadetregaskis/TUIkit that referenced this pull request Sep 2, 2026
205 upstream commits have landed since the fork point (6b22531, 2026-04-24) —
all of them in a four-day burst, 2026-07-19 to 07-22, across pull requests
phranck#44 to phranck#70. Reviewing that once is easy to start and impossible to finish
without somewhere to put the answer, and the question comes back every time
upstream moves again.

So: Documentation/Upstream-review/ holds the record, and
Tools/UpstreamReview/upstream-review.sh does the mechanical parts.

The tool enumerates every upstream-only commit oldest-first in TOPOLOGICAL
order, which is the load-bearing choice: it keeps a pull request's commits
contiguous and ahead of the merge that landed them, so each commit can be read
against the feature it belongs to. 169 of the 183 non-merge commits live inside
a PR branch; judged alone, "extract a helper" is unjudgeable.

Position is DERIVED from the ledger — reviewed means has a row — rather than
tracked beside it. A cursor and a ledger can disagree, and then neither can be
trusted.

`verify` checks the four ways this can rot:

  - a row naming a commit upstream no longer has (force-push or rebase);
  - the same commit recorded twice;
  - a HOLE behind the current position — the reviewed set must be a contiguous
    prefix of the enumeration, or "where we are" means nothing;
  - a verdict outside the vocabulary.

Each row carries a patch id as well as a hash, because a rebase preserves the
former and destroys the latter: an orphaned row can then be re-anchored instead
of re-reviewed.

Verdicts are a closed set (adopt / adapt / inspired / have / n-a / reject /
defer / queued / noise) so a typo cannot quietly invent a category, and the
`ours` column carries our own commit hashes so the ledger reads in both
directions.

Bash 3.2 throughout — macOS ships 3.2, and Tools/validate-test-boundaries.sh
already set that precedent.

Co-Authored-By: Claude <[email protected]>
wadetregaskis added a commit to wadetregaskis/TUIkit that referenced this pull request Sep 2, 2026
The tail — storage, view contracts, data flow, scenes — judged at branch
granularity, since by this point each branch's character was clear from
its first commit and per-commit detail would not have changed a verdict.

PR phranck#65's serialised writes are already ours (NSLock plus a serial save
queue). Its error reporting is not: we drop persistence failures on the
floor, so a read-only config directory looks like a successful save.
Deferred — real, small, unforced.

PRs phranck#67, phranck#69 and phranck#70 are deferred as a batch and explicitly NOT as
upstream-review work. They are all one thing — align the framework's
shape with SwiftUI's — and CLAUDE.md requires that to be answered against
the real SDK, which is how SwiftUI-compatibility.md was built. Reading
what upstream happened to write is the wrong instrument. Some of it is
already shipped here; DynamicProperty as a public protocol is not. The
next step is an audit pass over the data-flow and view-modifier surfaces
with these branches as one input among several, which is a piece of work
rather than triage.

Also fixes the ledger's row order: recording 8a73ec3 out of sequence
made `verify` report a gap, which is the check doing its job.

Final spread across 205 commits: 56 n-a, 37 noise, 35 have, 35 defer,
17 adapt, 16 reject, 5 queued, 4 inspired.

Co-Authored-By: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P1-14] Add composable Scene modifiers and Scene environment propagation .palette Modifier Cannot be Applied to WindowGroup

1 participant