Keep a component inside its boundary
WebForgers

A small label that shows “3 places left” was once taught to find the document title and append the count, because a public page wanted the count in the tab. With two cards on the screen, the tab flickered between them. The label had become an editor of the whole page.
The boundary
Write the boundary before the part is used in a second place.
A place count takes a number and a label. It shows that number and that label. If a person can activate it, it reports that fact, and the page decides what the activation means. The count reads its own inputs. The page title, a cart, and a neighboring card stay outside the boundary.
When the tab should carry the count, that is a different part, with its own input: the string the tab should show. The page can see both the card and the tab, and the page passes the string.
A filter and a list
A filter for morning and evening has to cooperate with a list. A shared box of state that both parts import has no boundary. Either part can write it, and the next person cannot see which one did.
The agreement is narrow. The filter emits “morning”, “evening”, or “any”. The list takes that value as an input and shows the matching rows. The page hears the emission and hands it to the list. A later line, “4 evening sessions”, can take the same value without the filter learning about summaries.
The page is the place that knows the parts. The parts know their inputs and their outcomes. The same limit shows up in product software, where a screen should not depend on the person who wired it: Software a coworker can run without a tour.
Name the inputs before the second use
Write the inputs as names before the part is dropped onto a second card. A place count takes a number and a label. It shows that number and that label. If it can be activated, the outcome is “activated,” and the page decides what that means. The page title is not an input unless a different part exists to receive a string for the tab.
If the only way to explain the part is “it looks around,” the boundary is not written yet. Looking around is how the tab flickered between two cards. The count on card A and the count on card B were both writing the same title.
A shared box is not an agreement
A filter and a list that both import a box can each write the box. The next person sees a value and cannot see who put it there. The narrower agreement is an emission and an input. The filter emits “morning,” “evening,” or “any.” The page hears it. The list receives it. A summary can receive the same value later, and the filter still does not know the summary exists.
Test that ignorance. Change the summary’s sentence. The filter’s file should not need an edit. If it does, the filter has learned about a neighbor, and the boundary has already leaked.
What leaks, in practice
Three leaks show up on a second screen.
The part reads the document title, a query in the address, or a cart it was not given. Those are page facts. Pass them in, or do not use them.
The part writes a neighbor. It hides a card, opens a tab, or appends a row in a list it does not own. Emit the fact. Let the page do the write.
The part imports the shared box “just for this one value.” The next feature will write a second value into the same box, and the first value will move at the wrong time.
The page keeps the wiring
The page is allowed to know every part, because the page is where the parts meet. A part is not allowed to know the page. When a third part arrives, the page grows one more handoff. The older parts keep the inputs they already had. That is the same restraint as a document that stays in meeting order while the paint moves: the structure is the agreement, and the picture is allowed to change around it. The order of the file is the other piece: Build the page in the order people meet it.
A second screen, same filter
The filter was built for one booking page. A second page, the week view, wants morning and evening too. The temptation is to import the filter and also import the box it already shares with the first list. Do not. The second page has its own list. The filter emits “morning,” “evening,” or “any” on both pages. Each page hears the emission and hands it to its own list. The filter does not learn the name of either page. If the week view needs a third value, “weekend,” that value is a new emission, agreed in the same place as the first three, not a field stuffed into the shared box because only the week view wanted it.
Write the emissions down before the second page uses them. A filter whose outputs are discovered by reading the code has no boundary yet. It has a habit. The habit will change under you the day the week view needs “weekend” and the booking page does not.
The label that rewrites the tab
A small part that sets the document title, or that writes the query string so it can read it back, is editing the page. The page owns the title and the address. If the filter’s current value should appear in the title, the filter emits the value and the page sets the title. If the value should survive a reload, the page writes the query, and the page passes the value back in as an input on the next load. The filter receives an input. It does not reach out to the address bar to find out who it is.
This is the leak that looks helpful. The feature works on the first page and then the week view opens with the booking page’s title, because the part still thinks it owns the document. Pass the title in, or do not touch it. There is no third option where the part “only sets it if it is empty.” Empty is a page fact too.
What the page may ignore
The page does not have to honor every emission immediately. It may ignore “morning” until the list has finished loading, and then apply it. The filter does not get to know about that wait. It emitted the value. The page’s timing is the page’s wiring. A filter that disables itself until the list says ready has learned about the list. That knowledge is the boundary failing in the other direction.
A summary that also wants “morning” subscribes through the page. The filter still emits once. The page fans the value out. If the summary and the list disagree, the bug is in the page’s fan-out, and you can see it because both inputs are written next to each other. A shared box hides that disagreement inside whoever wrote last.
The third part
When a third part arrives, a map, a price line, a note about what to bring, the page grows one handoff. The older parts keep the inputs they already had. You do not reopen the filter to teach it about the map. If the map needs “morning,” the page passes “morning” to the map as an input. The map does not import the filter to ask.
Name the inputs of the new part in the same note as the filter’s emissions, before the second use of the new part. A part used once can hide a leak. A part used twice cannot. The booking page and the week view are the two uses that make the boundary real. If you only have one page, write the inputs anyway, as if the week view were already scheduled. The scheduled page is what stops the shared box from looking like a shortcut.
If the week view slips and you still have only the booking page, keep the note anyway and review it when the second page is real. A boundary written for one page and “cleaned up later” does not get cleaned up. Later is when the shared box already has three values and nobody remembers which part writes which. The note is cheaper than that archaeology.
A value with nowhere to go
Sometimes the filter emits “morning” and the page has nowhere to put it yet, because the list is not on the screen. Hold the value on the page, in a variable that belongs to the page, and apply it when the list mounts. Do not tell the filter to wait, and do not drop the value on the floor. Dropping it means the person chose morning and the list arrived showing the whole day. Holding it on the page keeps the boundary: the filter has finished its job, the page has not finished its wiring.
If two emissions arrive before the list mounts, keep the later one. “Evening” after “morning” means evening. A queue of both, applied in order after mount, flashes the wrong list. The page stores one current value. That value is an input when the list is created, not a replay of history the list never asked for.