# the wrapper was conditional

One `Ishikawa → scientific method → Six Sigma` loop. The record below is the
commit message as written at the time, before the outcome was known to anyone
reading this file.

## Record — `4f7568b`

```
give a construct its after-crossing face, and let constructs compose

§6 records 62 persist-after-mutate sites, 10 auth-per-route, and
index-after-append that failed at 9 of 9 — every one an obligation at a
crossing that decayed into "remember to do this afterwards." An obligation a
human must remember is not an obligation, and the 9-of-9 figure is what that
costs.

    @decorator("injects_at_exit", "persist_now")
    fn durable() {}

The body moves into a static helper and the visible fn becomes a wrapper, so
EARLY RETURNS pass through the exit injection. Emitting it only before the
fall-through return would have silently missed every early return — the exact
failure class this seam exists to remove. Fns with no exit construct emit
byte-identically to before.

Three independent constructs now compose on one fn, none known to the compiler:

    el_val_t mutate(el_val_t k) {
      { el_val_t __g = my_auth(EL_STR("mutate"), EL_STR("authenticate")); if (__g) return __g; }
      engram_boundary_beat(EL_STR("mutate"), EL_STR("manager"));
      el_val_t __r = __el_body_mutate(k);
      persist_now(EL_STR("mutate"), EL_STR("durable"), __r);
      return __r;
    }

Guard, then entry, then body, then exit. §5.2 asked whether `hold` is one
construct or two; the implementation answers one construct with two faces,
selected by declared kind rather than by two mechanisms.

Verified: existing output byte-identical, compiler self-hosts byte-identically,
early returns pass through the exit, ordering holds under composition. 98/98
native compiler tests pass.
```

## Record — `285166c`

```
EXPERIMENT: emit the wrapper unconditionally, so exit binds at runtime too

ISHIKAWA: why did exit injection still need compile-time knowledge? Because the
body-helper wrapper was only emitted when codegen already knew an exit
construct existed. The wrapper being conditional was the cause, not the wrapper
being necessary.

PREDICTIONS AND RESULTS
  P1 exit becomes runtime-bindable                    TRUE  returns 14, bound
                                                            after the build
  P2 codegen shrinks                                  TRUE  5094 -> 5044
  P3 cost 5-15% from a call frame on every fn         FALSE 0.37s -> 0.38s, ~3%
  P4 fixpoint holds                                   TRUE

Every fn now gets a body helper and a wrapper. It has to be unconditional:
early returns must route through something for an exit construct to observe
them, and codegen cannot know which fns will be bound after the binary exists.

Removed with the machinery: declare_exit, decorator_exit, cg_exit_target,
cg_exit_construct, and the injects_at_exit scanner branch.

Two controls failed and were rewritten rather than repaired --
no-exit-construct-emits-no-wrapper asserted the optimisation this removes, so
it is now inverted. The integration harness gained a seventh assertion: an exit
construct declared after the build replaces the result.

99/99 native, 7/7 integration, fixpoint gen2==gen3.
```

## Record — `b40754f`

```
land unconditional wrapper: exit crossings resolve at runtime
```
