Chapter 8 is a lab, not a fresh application. Start with the completed Chapter 7 filters-and-reducers checkpoint, then deliberately make one pipeline filter fail. The exercise shows how a FeatureCell™ can expose a finalized feature error while the UI remains an observer rather than a second source of pipeline authority.
You will keep the Chapter 7 CRUD workflow, pure filter, and ordered reducers. The lab adds one intentional throwing filter, an errors() callback, and a global error response. The point is to watch the same service-owned boundary handle failure, then prove that clearing a message is not the same as removing the cause.
Key takeaway: Use the pipeline to own failure and finalization, use
errors()to observe feature-specific output, and use application-level error state for shared visibility. A UI acknowledgement should not pretend that the underlying cause has been repaired.
What Chapter 7 Already Gives You
In Chapter 7, Resolve produces the incoming character collection, Filters removes the teaching record whose last name is unknown, and Reducers derive the display-ready collection. The service registers those rules, while the component consumes the committed State for selection, editing, and rendering.
That completed checkpoint matters because Chapter 8 does not replace the data flow. It places a controlled failure into the existing filter path. Every later create, update, or delete request still enters through the same service methods and reaches the same pipeline. When the teaching flag is enabled, the candidate fails before it can become committed State.
| Existing checkpoint | What the lab adds |
|---|---|
| Service-owned FeatureCell | A controlled failure inside the registered filter path |
| Pure filter and ordered reducers | A filter that throws only while the teaching flag is armed |
| Component renders committed State | Component observes global and feature-specific error outputs |
| Normal CRUD requests | Reset action that disarms the cause without another request |
⚠️ Warning: Do not copy the failure pattern into ordinary validation. The lab throws deliberately so the Error stage is visible. Expected invalid form or domain input should use the documented validation or rejection mechanism instead of unexpected exceptions.
Lab Step 1: Arm a Controlled Pipeline Failure
Begin in the Chapter 7 service. Keep the existing removeUnknownLastNameFilter, then add a second inline filter after it. Most of the time this filter returns the candidate unchanged. When the signal-backed teaching flag is enabled, it throws an intentional error.
The component does not construct a special failed request. The service arms the flag and submits a fresh replacement candidate with replaceState(). That fresh identity makes each demonstration attempt observable, while the enabled filter stops the candidate before State commitment.
This is the important lab boundary: the failure is part of the pipeline configuration, not a component-side branch around normal CRUD behavior. Once armed, later create, update, and delete calls continue to enter the same failing filter until you reset it.
Key takeaway: A global banner may tell the user that something failed, but the enabled throwing filter explains why the next candidate will fail too. Observe the cause, not just the symptom.
Lab Step 2: Register an Observational Error Callback
The Chapter 8 service registers an errors() callback alongside the existing filter and reducer registrations. The callback receives the finalized Vault error and the immutable FeatureCell snapshot after error handling has completed. It records those values for the tutorial output; it does not transform the error, replace State, or decide whether the pipeline should continue.
The documented method contract is deliberately small. Use it for observation such as diagnostics, monitoring, logging, or a compatibility bridge. Keep error authority in the pipeline and keep presentation decisions in the component.
employeeCell
.errors([
(error, state) => {
console.error('Employee FeatureCell error:', error.message);
console.info('Last known state:', state.value);
}
])
.initialize();
In the lab's Angular service, the equivalent callback stores the error and snapshot in a read-only teaching signal. The component serializes that signal into the Error Emission output so you can inspect what was finalized without giving the template permission to mutate it.
Lab Step 3: Compare Two Error Surfaces
The lab displays two related but separate results. First, VaultErrorService exposes application-level error state. The component subscribes to its global stream and uses it for the visible error banner. That singleton is independent of any one FeatureCell, which makes it suitable for shared application concerns such as monitoring, banners, and recovery guidance.
Second, the service-owned errors() callback emits the finalized error together with the FeatureCell snapshot. That output is specific to this feature and this lab. It is useful for understanding what the pipeline finalized, but it is not a replacement for the application-level error surface.
| Surface | Consumer | Responsibility |
|---|---|---|
| Finalized FeatureCell error |
errors() callback |
Observe the error and immutable snapshot for feature-specific work |
| Global Vault error | VaultErrorService |
Present application-level status or shared operational feedback |
| User-facing message | Component template | Show an actionable, non-sensitive summary and acknowledgement control |
⚠️ Warning: Redact before telemetry. Raw exceptions and State snapshots can contain credentials, personal data, or domain secrets. Render a safe message for the user and define a separate redacted diagnostic payload for operators.
Lab Step 4: Prove That Clear Is Not Recovery
Click Throw Error and observe the global error banner and the serialized Error Emission output. Then try an add, edit, or delete action while the control reads Reset Error. The same pipeline failure should appear again because the filter is still armed.
Now click Clear. The banner disappears, but the cause remains enabled. Trigger another mutation and the failure returns. Clearing the singleton error acknowledges the current message; it does not disable the filter or retry the failed candidate.
Finally, click Reset Error. The service disarms the throwing filter and clears the global error without sending another pipeline request. Later CRUD actions now pass through the original Chapter 7 filter-and-reducer flow and can commit normally again.
Key takeaway: Throw Error, try a CRUD action, Clear, try another CRUD action, Reset Error, then try CRUD again. The sequence separates acknowledgement from recovery in a way a static error banner cannot.
The Chapter 8 Lab Takeaway
Chapter 8 builds directly on the completed Chapter 7 lab checkpoint: the same service-owned FeatureCell, the same character collection, the same filter and reducers, and the same CRUD requests. The new work is a focused experiment in failure observation. You deliberately arm one filter, watch the Error stage finalize the failure, compare feature-level and application-level outputs, and then remove the cause.
The resulting boundary is practical beyond the tutorial. Pipelines should own error authority and finalization. Services should register the feature's observational hooks. Components should present safe feedback and local acknowledgement state. Recovery should change the failing condition or explicitly retry according to a defined policy; dismissing a message alone should not pretend that the underlying operation succeeded.
Save this completed checkpoint before moving to Chapter 9: Async Input. The next lab carries the same error model into asynchronous inputs.
Deeper Dive
Continue with the errors() method reference, Global Error Handler, and the complete Chapter 8 lab.
Top comments (0)