Skip to content

fix(generator): stop shipping [Remote] bodies to trimmed clients for [Execute] and [FactoryEventHandler<T>] (TRIM-008) - #75

Merged
keithdv merged 11 commits into
mainfrom
TRIM-008-registrar-dam-over-preservation
Aug 14, 2026
Merged

fix(generator): stop shipping [Remote] bodies to trimmed clients for [Execute] and [FactoryEventHandler<T>] (TRIM-008)#75
keithdv merged 11 commits into
mainfrom
TRIM-008-registrar-dam-over-preservation

Conversation

@keithdv

@keithdv keithdv commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What was wrong

[assembly: NeatooFactoryRegistrar(typeof(T))] carries [DynamicallyAccessedMembers(PublicMethods | NonPublicMethods)], which preserves every method on the named type, bodies included.

Class and interface factories name the generated {X}Factory. Static [Factory] classes and [FactoryEventHandler<T>] classes have no separate generated type — the generator re-opens the user's own partial to host FactoryServiceRegistrar — so the attribute named the consumer's class, and their [Remote] server-only bodies shipped to Blazor WASM clients decompilable. Since v0.21.2 (2026-03-08).

This is the plan that makes RemoteFactory's headline IP-protection claim true for those two shapes.

The fix

A generated top-level forwarding holder per leg, with the attribute pointing at it, so preservation reaches one method instead of everything on the user's class:

internal static class NeatooFactoryRegistrar_MyCommands
{
    internal static void FactoryServiceRegistrar(IServiceCollection services, NeatooFactory remoteLocal)
        => MyCommands.FactoryServiceRegistrar(services, remoteLocal);
}

Forwarding rather than hosting because [Execute] methods are private static by the repo's own convention and the registrar body calls them — a hosting sibling would be CS0122. Distinct prefix per leg (NeatooFactoryRegistrar_ / NeatooEventHandlerRegistrar_) so a class carrying both attributes doesn't gain a CS0101 on top of its existing CS0111. The relay leg's long-missing global:: qualifier is fixed at the same time.

Two generator files changed; no model, builder, or transform touched. git diff --name-only 25ac975..HEAD -- src/Generator/ returns exactly those two.

Evidence

Measured on publish-trimmed artifacts, present-before / absent-after:

Leg Pre-fix Post-fix
[Execute] static factory _DoWork, _ProcessRecord, IServerOnlyRepository, DoServerWork present all absent
[FactoryEventHandler<T>] all four relay markers present all absent
Interface factory absent absent (no regression)

Emission delta over both solutions: 732 files, 40 changed (20 relay, 20 static), 692 byte-identical, no class- or interface-factory output in the delta — and every changed line matched against the two permitted shapes, zero outside them.

What this does NOT deliver

AC6 is not closed. The pre-fix probe found a third broken shape by a different mechanism: async generated Local* class-factory methods retain their server-only bodies. A controlled experiment (same class, same factory, no auth either side, one-hop rooting both, direct concrete call both — differing only in async-shaped emission) confirmed it. Carried as TRIM-009; the v1.7.0 release stays blocked on it.

The trimming gate asserts those markers PRESENT on purpose, so CI fails loudly the moment TRIM-009 lands rather than silently passing.

Also in this PR

  • CI gate rewritten into verify-trimmed.sh so it can be run against known-bad artifacts and observed failing. Searches two encodings — body string literals are UTF-16 and grep -a can never match them, which would have made every literal check pass unconditionally. Carries positive controls covering both extraction paths, exits at the controls rather than emitting remediation advice on an untrustworthy artifact, and names the leg on failure. The (?<!I)ServerOnlyRepository exemption is deleted — it was justified by a diagnosis this arc disproved.
  • Registrar attribute contract written into its XML docs: the Type must be a generated registrar type, never a consumer type.
  • ~40 documentation anchors corrected across four buckets, including the distributable skill and src/Design/. Both docs/trimming.md and the skill also gained the UTF-16 caveat for readers verifying their own builds.
  • Harness legs added for relay-handler, interface-factory, Save/Can*, and async variants of each, with per-leg server-only ports so a failure names one culprit.
  • Two new latent bugs recorded, not fixed: [Service] params on interface-factory methods emit uncompilable code (CS0535), and the interface leg is structurally unable to measure body elimination.

Gates

plan-reviewer (CONCERNS, 5 veto) plus test-reviewer and code-reviewer at three passes each. Records and archived evidence in docs/todos/TRIM-dto-trimming-preservation-gaps/reviews/.

611+611 unit, 561+561 integration, 86+86 Design, 0 failed, nothing filtered. Trimmed harness exits 0.

Note for the merge run: the gate has only been exercised on win-x64; this is its first linux-x64 run. A failure there is informative, not a falsification of TRIM-009.

🤖 Generated with Claude Code

keithdv and others added 11 commits August 12, 2026 22:22
…e arc

Reverses the 2026-08-11 routing that sent the registrar-DAM defect to plan
mode outside any todo. Three things made that untenable: the defect is
release-blocking, so the arc cannot close without it; it falsifies the
documentation AC4 requires be accurate, so AC4 cannot close honestly while it
stands; and the close-out audit found its only record was a Discovery Log
entry that archives when the todo closes — it would have lost its tracker at
exactly the moment it still mattered.

Adds AC6 to the todo, making the IP guarantee a named requirement. Notes why
that is not scope creep: AC1-AC3 are about preservation (making types survive
trimming), AC6 is about over-preservation (stopping code surviving that should
not) — opposite failure modes of the same mechanism.

The plan uses a top-level generated holder that FORWARDS to the existing
registrar, not the nested type floated at TRIM-005's review. Two reasons.
The nested variant rests on "DAM does not extend to nested types", which this
codebase has never verified and which the TRIM-007 precedent does not prove
since that holder is top-level. And design work found the advisory's unstated
second reason for nesting: [Execute] methods are private static by the repo's
own convention and the registrar body calls them, so a sibling holder that
hosts the registrar is CS0122. Forwarding satisfies both without depending on
unverified ILLink behavior, and removes no member, so it is fix: not feat!:.

Records two latent generator bugs found during design and deliberately not
fixed: nested [Factory] static / handler classes emit uncompilable code, and
a class carrying both attributes emits CS0111. Both pre-existing.

Deferred items 1, 6, 7, 8 now route to TRIM-008; 14 and 15 added.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ing holder

The assembly attribute's [DynamicallyAccessedMembers] preserves every method
on whatever type it names, bodies included. StaticFactoryRenderer named the
consumer's own [Factory] class, so ILLink retained their [Remote] server-only
method bodies and shipped them to trimmed browser clients, decompilable —
contradicting the IP-protection guarantee the docs advertise.

Emits a top-level `internal static class NeatooFactoryRegistrar_{TypeName}`
whose single method forwards to the FactoryServiceRegistrar that stays on the
user's partial class, and points the attribute there. The DAM blast radius
becomes that one forwarding method.

Forwarding rather than hosting is required: [Execute] methods are private
static by the repo's own convention and the registrar body calls them, so a
sibling type that hosted the registrar would be CS0122. Forwarding also
removes no member, so this is fix: rather than feat!:.

Measured, not inferred. Publish-trimmed win-x64, TrimMode=full,
IsServerRuntime=false, diffed against an archived pre-fix artifact:

  _DoWork                PRESENT -> absent
  _ProcessRecord         PRESENT -> absent
  IServerOnlyRepository  PRESENT -> absent
  DoServerWork           PRESENT -> absent
  TrimTestCommands       PRESENT -> PRESENT   (delegates still rooted)
  TrimRecordResult       PRESENT -> PRESENT   (AC1 intact)
  NeatooEventPreservation PRESENT -> PRESENT  (AC3 intact)

Harness exits 0 with ValidateOnBuild=true and resolves the static delegate,
so registration still works through the indirection. This also settles the
open question of whether ILLink applies feature-switch substitution to a
method reached only by a call from a DAM-preserved method: it does.

The holder is named with a PREFIX deliberately. A suffix form leaves
global::Ns.{TypeName} a substring of the holder's own FQN, which would make
the "attribute must not name the consumer's type" regression assertion a
false red and an unclosed Contains a false green.

Plan review returned CONCERNS with 5 veto findings; all are folded into the
plan before further implementation. The most consequential reordered the
steps: harness targets and their pre-fix probe must precede the leg that
fixes them, because a marker first measured after the fix cannot distinguish
"the fix removed it" from "it was never rooted".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…pre-fix

Plan-review B1 required every new marker to have a pre-fix baseline before
the leg that fixes it lands. Three legs added, each with its own server-only
port so a marker names one culprit, then probed publish-trimmed with the
relay leg still unfixed.

Results:
- relay leg: all four markers present. The baseline Step 4 needs.
- interface-factory leg: all five markers absent. The arc's structural claim
  about this leg is now a measurement (closes half of B9).
- Save/Can* leg: PRESENT, unexpectedly. Async generated Local* methods retain
  their server-only bodies; sync ones in the same assembly do not. Rooted by
  the class-factory registrar's own unguarded delegate closures, so this is a
  different defect from TRIM-008's and the holder fix does not reach it.
  Carried as deferred item 18; blocks AC6 as worded.

The probe's self-check against the untrimmed assembly caught a defect in the
probe itself: it decoded UTF-16 only from byte offset 0, so every string
literal at an odd offset was invisible and reported "absent". Uncorrected it
would have reported the Save/Can* break as a clean pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…TRIM-009

User decision. The alternative was narrowing AC6 to the two shapes TRIM-008
owns and shipping v1.7.0 sooner with a disclosure. Rejected: the leaking
shape is the class factory, which the docs, the skill, and CLAUDE-DESIGN.md
all hold up as the shape that works. A release closing AC4 while that claim
stays false is what AC6 exists to prevent.

- AC6 reworded to name all three broken shapes; routes to TRIM-008 + TRIM-009
- TRIM-009 stub added, carrying the measured evidence and the controlled
  sync-vs-async comparison, with no remedy prescribed
- Deferred item 18 routed to TRIM-009; item 2 (release held) widened
- TRIM-008 scope corrected: it no longer unblocks the release by itself and
  must not be closed out as delivering AC6

TRIM-008 is unchanged in scope and continues at Step 4. TRIM-009 inherits the
2026-08-13 pre-fix baseline rather than needing its own probe.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ng holder

Second and last leg of the registrar-DAM fix. The [FactoryEventHandler<T>]
assembly attribute named the consumer's own handler class, so DAM retained
every method on it including the handler body and the server-only service it
reaches. Adds a forwarding holder and the long-missing global:: qualifier.

Holder prefix is NeatooEventHandlerRegistrar_, deliberately distinct from the
static leg's NeatooFactoryRegistrar_: a class carrying both [Factory] and
[FactoryEventHandler<T>] already emits duplicate registrars (CS0111, broken at
HEAD, deferred item 15), and a shared prefix would stack CS0101 on top.

Measured publish-trimmed, present-before/absent-after on all four relay markers
including the body's string literal. Interface-factory markers absent in both
probes (no regression); Save/Can* markers present in both, as TRIM-009 predicts.

Tests (the relay leg had none before):
- StaticFactory_EmitsAssemblyAttribute retargeted, intent preserved
- new: attribute does not name the consumer type, on both legs
- new: holder forwards to the user's registrar, on both legs
- new: relay output compiles without errors

Proven non-vacuous: with the renderer reverted, the three relay emission tests
go red and the other eight stay green.

DiagnosticTestHelper gains DI/Logging/ComponentModel references. Without them no
generated tree could compile in this harness, so "generated code is valid" was
not an assertion anyone could have written — which matters most for the relay
renderer, whose output bypasses NormalizeWhitespace and whose parse failures are
swallowed into a comment rather than thrown.

FactoryEventRelayTests flakes under full-suite parallel load (deferred item 10).
Verified pre-existing: identical failures with this change stashed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ing gate

Step 5 — NeatooFactoryRegistrarAttribute now states the rule that was only ever
implicit: the Type must be a generated registrar type, never a consumer's class,
because [DynamicallyAccessedMembers] retains every method on it, bodies included.
Documented with the reason rather than as a bare rule, plus the two points a
future editor would otherwise re-litigate — why the DAM is deliberately not
narrowed, and that the method name is a literal looked up with a null-conditional
invoke, so a rename fails silently.

No API surface changes: XML documentation only. No member added, removed,
renamed, or re-annotated.

Step 8 — the (?<!I)ServerOnlyRepository exemption is deleted. It was justified by
the TRIM-005 diagnosis this arc disproved; the real cause was the static-factory
registrar naming the consumer's class. With that fixed, IServerOnlyRepository is
measured absent and now asserted absent.

The gate moved from shell-in-YAML into verify-trimmed.sh, which is the point: the
acceptance bullet carried [explicit-skip: not unit-testable], and that skip is
how the old gate shipped with an untestable exemption and a grep -aq that printed
success on a missing path. The script was run against archived artifacts and
observed FAILING four ways — pre-fix relay DLL names the relay leg, pre-static-fix
DLL names the static leg, missing path fails loudly, fixed DLL passes.

It searches two encodings. Metadata names are UTF-8; body string literals are
UTF-16LE, which grep -a on raw bytes can never match — the obvious gate would
report every literal marker absent and pass unconditionally. tr -d '\000' gives a
second view, and three positive controls cover both extraction paths so a failure
in either is caught rather than silently disabling half the gate.

Save/Can* markers are asserted PRESENT on purpose: omitted, the gate would keep
passing after TRIM-009 lands. Asserted, CI fails the moment the leak is fixed and
says to promote them. A pending marker, not an endorsement.

.gitattributes pins *.sh to LF so a CRLF checkout cannot break the gate with a
"bad interpreter" error that reads like a missing shell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Step 9 and Step 10 of TRIM-008, plus the emission delta evidence.

The ~40-anchor inventory was rebuilt by reading the files rather than copying
the plan's list (plan review A4), and recorded at
reviews/008-doc-anchor-inventory.md. It falsified the plan's own "verified
do-NOT-touch" list: the class-factory anchors there are false today because of
TRIM-009. Deferred to TRIM-009 with the eight anchors enumerated and
release-blocking, rather than edited now and reverted after.

Corrections:
- Static/relay per-shape claims, plus the holder mechanism, in docs/trimming.md
  and CLAUDE-DESIGN.md — whose attribute-target table had documented the defect
  as intended design ("the static class itself").
- The four falsified-TRIM-005 artifacts. ServerOnlyTypes.cs needed no change: it
  said the interface should be absent, contradicting the other three, and was
  right the whole time.
- Five silences: ExecuteAttribute and FactoryEventHandlerAttribute<T> XML docs,
  attributes-reference.md, the skill's static-factory and trimming pages, and
  AllPatterns.cs.
- Bucket 4 — "preserve all methods on the referenced type" now says which type
  that is and why it is never the consumer's.

Two things users were never told, now documented: [Remote] is decorative on
[Execute] (the IsServerRuntime guard makes the body trimmable, not the
attribute), and the [FactoryEventHandler<T>] leg cannot be verified from a
client-side test because every registration is server-guarded.

Both docs pages told readers to grep the published DLL for server-only names.
That works for metadata names (UTF-8) and silently fails for string literals
(UTF-16) — the same trap that nearly made our own probe report a broken leg as
clean. Both now carry the tr -d '\000' step and say to prove the check against
an untrimmed build first.

Emission delta, measured over both solutions with the generator reverted to
25ac975 and again at HEAD: 732 files emitted, 40 changed (20 relay, 20 static),
692 byte-identical, no class- or interface-factory output in the delta. Checked
one level stronger than the acceptance bullet asked — every changed line matched
against the two permitted shapes, 0 outside them.

Container: deferred items 6 and 7 closed, item 8 partially closed with its
premise corrected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ten acceptance bullets mapped to the tests or measurements that discharge them.
Two tiers upgraded rather than skipped: the emission byte-identity bullet was
measured instead of explicit-skipped, and the CI-gate bullet's "shell in YAML,
not unit-testable" skip is retired now that the gate is a script exercised
against archived known-bad artifacts.

Records one deliberate gap: nothing rejects a CONSUMER hand-writing
[NeatooFactoryRegistrar] against their own type. The Step 5 contract is
documentation, not a diagnostic. Generator regressions are caught by the two
DoesNotNameConsumerType tests; hand-written consumer usage is not caught at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both gates ran; every checkable finding was re-verified at the keyboard before
being accepted, and all held.

The measurement that changed a diagnosis: adding async targets to three legs
(P2/S7) contradicted TRIM-009's stated cause. Async [Execute], async relay
handlers, and an async interface-factory method ALL trim clean — only the
class-factory write path leaks. It narrows rather than falsifies: none of the
clean shapes is the leaking shape (static/relay use a wrapping guard in a
non-async registrar; the interface leg reaches its impl through an interface,
so no body is statically reachable). The leak needs an early-throw guard AND
async AND a direct call on a concrete type. TRIM-009's stub now carries the
five-shape table and is told not to treat "async is the cause" as settled.

Veto-tier:
- V1: the rewritten gate had silently dropped a marker the old one carried —
  grep -F "IServerOnlyRepository" cannot match the bare implementation name that
  (?<!I)ServerOnlyRepository existed to catch. A coverage regression inside the
  artifact this plan calls its Step-8 deliverable, narrated as strengthening.
  ServerOnlyRepository_MARKER restored, measured PRESENT untrimmed first.
- V2: RelayLegBackend was reported as a present->absent pair; the probe recorded
  it absent both times. Four discriminators, not five. Gate now labels every
  marker [D] or [R]; the blanket "measured PRESENT before, ABSENT after" header
  was wrong for 8 of 16.
- V3: two claims added by this plan implied that naming a *generated* type is
  what makes a leg safe. It isn't — {X}Factory is generated and hosts every
  Local* method. Reworded; the unqualified "no documentation asserts..." bullet
  scoped to the two shapes this plan delivers.

Must-cover:
- P1/C2: the holder's method name was not pinned despite the Constraint and the
  test's own remarks claiming it was — the user's partial emits a byte-identical
  signature. Both tests now anchor it to the holder's class declaration; proven
  by renaming only the holder's method and observing RED.
- P3: ServerOnlyHelper had zero references, so its absence was unconditional
  while serving as evidence. Wired into DoServerWork so the transitive-removal
  property it claimed is actually tested.
- S8: TrimTestEntity gets its own IClassLegPort so class-factory leaks stop
  reporting as static-factory failures — matters now that TRIM-009 edits it.
- S5/S6/S9: relay compile test no longer passes on zero trees; private-handler
  fixture added; both-attributes CS0111-without-CS0101 claim now pinned.
- C4/S10: integration counts corrected to 561+561, nothing filtered.
- C5: all four gate runs captured.

Accepted with reason: C3 (gate exercised win-x64 only, CI is linux-x64),
C6 (BuildReferences widening changes the semantic model suite-wide),
C7 (nested/global/generic shapes traced, not assumed).

611+611 unit, 561+561 integration, 86+86 Design, harness exit 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rms async

Both gates re-ran. Every checkable finding re-verified at the keyboard first;
all held. This round changed no generator source — only harness, gate, tests,
and docs — so the byte-identity and incremental-cache conclusions stand.

THE CONTROLLED EXPERIMENT (V5c). The code review showed my three-condition
narrowing was unsupported: two conjuncts rested on rows that cannot
discriminate, and the class-factory pair I called "single-variable" actually
differed in four more ways — an auth block, target-from-DI vs from-parameter,
one-hop vs two-hop rooting (there is no InsertDelegate), and an extra catch arm
plus lifecycle probes. That last is the dimension the arc's disproven TRIM-004
story blamed.

TrimTestEntity now carries an async [Remote][Fetch] beside its sync
[Remote][Create], each writing its own literal into its own body. Same type,
same factory, same registrar, no auth either side, one-hop rooting both, direct
concrete call both. Trimmed: sync marker ABSENT, async marker PRESENT; both
PRESENT untrimmed. async is confirmed as the operative variable, now on a
controlled comparison. TRIM-009's scope is right — for a better reason than
the one it was created with.

Still unestablished, and now said so: whether the guard shape and the direct-
concrete-call shape are NECESSARY. Neither has independent evidence.

Other findings:
- V4: [D]/[R] labels were themselves wrong — IServerOnlyRepository and
  DoServerWork were present pre-fix, so they are discriminators, and the marker
  whose flip is Step 8's headline evidence was under-claimed. Added [N] for
  new-baseline markers that never had a pre-fix measurement.
- V6: the gate's success line claimed async class-factory coverage that did not
  exist. Now true, and states exactly which bodies are absent vs expected-present.
- V7: the "necessary, not sufficient" paragraph reached CLAUDE-DESIGN.md but not
  the published docs/trimming.md. Ported.
- C9: the container never received the async result. Deferred item 18 rewritten;
  Discovery Log entry records the reversal, not just the endpoint.
- C10: positive controls named in full — the prefix control was satisfied by the
  sync handler class alone; added DoAsyncWork and async-iface resolutions.
- C11: "untrimmed-PRESENT so it can fail" is unsound — ServerOnlyHelper was
  untrimmed-PRESENT for months and still could not fail. Header narrowed.
- N1/item 19: [Service] on interface-factory methods emits uncompilable code
  (CS0535). Found trying to give that leg a reachable marker; it means the leg
  is STRUCTURALLY unable to measure body elimination. Recorded, stated at the
  target and in the gate rather than left to be inferred from a clean result.
- N2/N3/C12/C13/C15: fixture-drift guard, async-iface resolution check, stale
  numbers and artifact names, probe header.

Gate re-validated four ways: passes on the fixed artifact, fails naming the
relay leg, fails naming the static leg, fails on a missing path. It also caught
its own new consequence on first run — IClassLegPort/ClassLegInvoke flipped to
present once FetchAsync existed, which is per-leg attribution working.

611+611 unit, 86+86 Design, harness exit 0. One FactoryEventRelayTests failure
on net9.0 only, passing in isolation — the deferred item 10 flake, already
proven pre-existing by stashing this branch's changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…d AC

Third pass on both reviewers. Both reached the same verdict: the deliverable
was done, the bookkeeping was not. Every checkable finding re-verified at the
keyboard first; all held.

Two real defects, not bookkeeping:

- The gate ran its assert-PRESENT blocks AFTER positive controls failed, so an
  archived artifact that predates the current targets emitted eight "the async
  diagnosis is wrong and must be reopened" instructions. Printing "do not trust
  the results below" and then printing them anyway is not enough when the text
  below is the most action-directing in the gate. It now exits at the controls.
  Consequence: the old red transcripts no longer demonstrate per-leg naming, so
  a better demonstration replaces them — current code published with the feature
  switch left ON, where all 6 controls pass and the gate names every leg across
  30 errors (gate-red-nofold.txt).

- AC6 and the release-blocking doc inventory both said "async WRITE operations".
  FetchAsync is a [Fetch] — a read — and it leaks. Widened to any async
  operation; the criterion that gates the release was understating the defect.

The async conclusion is restated as "async-SHAPED emission". Five constructs are
async-only in the generated body: the extra catch arm and four interface
type-tests (IFactoryOnStartAsync/OnCompleteAsync/OnCancelled/OnCancelledAsync).
Type-tests are a different ILLink retention mechanism from a state machine, so
two hypotheses survive and the experiment cannot separate them — one of them the
disproven TRIM-004 story returning in async-only form. They imply different
fixes, so TRIM-009's first step is now to separate them from inside the
generator. Also recorded: DAM roots LocalFetchAsync via typeof(factory), so
de-rooting is not an available remedy.

Also: the controlled pair's service asymmetry is load-bearing and now documented
as do-not-tidy (symmetry would turn the static-factory [D] markers red for a
misleading reason); the Test Evidence [D]/[R] row contradicted the script it
described and is corrected; artifacts are cited by role against a manifest after
three consecutive passes of stale filenames.

Gate records written (008-test-review.md, 008-code-review.md) with evidence
archived in 008-evidence/ — every other gated plan in this arc had both and this
one asserted them without records. Plan and index moved to Done.

TRIM-008 delivers two of AC6's three shapes and is NOT closed out as delivering
AC6. The release stays blocked on TRIM-009.

611+611 unit, 561+561 integration, 86+86 Design, 0 failed, nothing filtered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@keithdv
keithdv merged commit 2e50546 into main Aug 14, 2026
2 checks passed
@keithdv
keithdv deleted the TRIM-008-registrar-dam-over-preservation branch August 14, 2026 01:14
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