Skip to content

refactor(layers): declare RuntimeRenderInput — the ledger's licensed input (#493 PR-2) - #502

Merged
Juliusolsson05 merged 1 commit into
mainfrom
refactor/render-input-contract
Jul 9, 2026
Merged

Juliusolsson05 merged 1 commit into
mainfrom
refactor/render-input-contract

Conversation

@Juliusolsson05

Copy link
Copy Markdown
Owner

Part 2 of 3 for #493, stacked on #501. Plan: docs/superpowers/plans/2026-07-09-layer-isolation.md §3.

What

The contract. RuntimeRenderInput in session-runtime/state.ts — the declared seven-field slice the DECIDE layer may read (entries · semantic · ghosts · streamPhase · streamPhasePendingToolName · streamPhasePendingToolUseId · lastJsonlEntryAt). It is exactly what the pipeline reads today (from useLedgerFeedItems' slice assembly + ledgerFeedContextFromRuntime) — deliberately NOT the issue's speculative list (conditions/screen/totalEntries have no decide-layer reader; including them would license future back-door reads). A Pick (+ a ReadonlyMap ghosts field — the decide layer only reads the ghost plane), so desktop callers pass the same runtime object unchanged and the D11 reference-identity chain is untouched.

Both as unknown as SessionRuntime casts are dead:

  • replay's runtimeViewFor now builds an honestly-typed RuntimeRenderInput — and gained the lastJsonlEntryAt + full-semantic fields the cast had been hiding the absence of;
  • the phone's SessionView runtime view is exactly typed; the remote store now mirrors the full SemanticRuntimeState into its snapshot (same ticks as the existing scalar mirrors) so semantic is the real fold state, not a fabricated partial.

Last value-level rendering→feed edge cut. isAgentSpawnToolName moved from features/feed/lib/ into providers/registry.renderer.capabilities.ts — it's a pure union over each provider's isSpawnTool capability, i.e. provider vocabulary that registry owns. The committed collector and the feed rows share it through the providers layer, which both legally import. (tsconfig node exclude + web include updated so the relocated test keeps exactly its previous type-check coverage — providers-root files are reached by no glob.)

Dead code deleted (plan D6): rendering/policy/foldPolicy.ts + test — zero consumers since the Stage-3 cutover.

Verified

grep -rn "@renderer/workspace" src/renderer/src/rendering/                       # → empty
# value imports of session-runtime in rendering/ production code: replay/ only (sanctioned reducer reuse)

Gates: tsc node+web clean · vitest 467/467 (delta from PR-1 = foldPolicy's own tests went with it) · remote-client build OK.

Remaining after this: PR-3 flips the output seam (rendering/view/ → features/feed/ledger/).

🤖 Generated with Claude Code

…input contract (#493 PR-2)

The decide layer's input is now a DECLARED seven-field pick instead of an
undeclared reach into the whole SessionRuntime:

- session-runtime/state.ts: RuntimeRenderInput = Pick<SessionRuntime,
  entries | semantic | ghosts | streamPhase | streamPhasePendingToolName |
  streamPhasePendingToolUseId | lastJsonlEntryAt> — exactly what the
  pipeline reads today, nothing speculative. A Pick (not a wrapper) so
  callers pass the SAME object and the D11 reference-identity chain is
  untouched.
- useLedgerFeedItems / ledgerFeedContextFromRuntime / replay's
  runtimeViewFor now take RuntimeRenderInput. Both former
  `as unknown as SessionRuntime` casts are gone: replay's runtimeViewFor
  builds an honestly-typed object (and gained the lastJsonlEntryAt +
  full-semantic fields the cast was hiding the absence of).

Cut the last value-level rendering -> features/feed edge:
- isAgentSpawnToolName moved from features/feed/lib/agentSpawnTools.ts
  into providers/registry.renderer.capabilities.ts — it is a pure union
  over each provider's isSpawnTool capability, i.e. provider vocabulary
  owned by that registry. The committed collector and the feed rows now
  share it through the providers layer, which both may legally import.
  tsconfig node exclude + web include updated so the relocated test stays
  exactly as type-checked as before (providers-root files are reached by
  no glob; the node project must NOT walk it — same rationale as the
  registry's own exclude).

Deleted dead code (plan D6): rendering/policy/foldPolicy.ts + test — zero
consumers since the Stage-3 cutover; the D10 provider-asymmetry idea it
encoded lives on as the actively-consumed semanticFoldPolicy provider
capability. Git history preserves it.

Gates: tsc node+web clean, vitest 467/467 (delta from PR-1 = foldPolicy's
own 9 tests deleted with it), remote-client build OK.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Base automatically changed from refactor/layer-isolation to main July 9, 2026 08:24
@Juliusolsson05
Juliusolsson05 changed the base branch from refactor/layer-isolation to main July 9, 2026 08:24
@Juliusolsson05
Juliusolsson05 merged commit e913235 into main Jul 9, 2026
@Juliusolsson05
Juliusolsson05 deleted the refactor/render-input-contract branch July 9, 2026 08:24
Juliusolsson05 added a commit that referenced this pull request Jul 9, 2026
…ack + #498 paste fix)

One conflict, SessionView.tsx imports: union of this branch's chrome
imports (PaneHeader/ComposerInput/useComposerAutoGrow) with main's
post-#493 paths — useLedgerFeedItems now lives in features/feed/ledger,
the runtime view types against RuntimeRenderInput from
session-runtime/state (the SessionRuntime cast died in #502), and
NO_GHOSTS is ReadonlyMap<string, GhostEntry>. The file body auto-merged
main's honestly-typed runtimeView (semantic: transcript.semantic) under
this branch's chrome unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant