You are right on all four points. I checked them on the real policies rather than on reconstructed joints, then went further, and going further refuted a hypothesis of mine and produced a mechanism. Everything below is in the repo.
The coverage artifact, confirmed. moyenne_cond_det is an unweighted mean over six determiners and a softmax never reaches zero, so the dead rows clear the total > 0 guard and enter with full weight. On the eight runs where I have the complete analysis, the value is (determiners emitted)/6 to four decimals: 0.3333 for two live determiners, 0.6667 for four. And exactly as you say, a 12-mode singular collapse and a 24-mode plural collapse both read 0.3333, which is precisely the distinction the number was carrying in my sentence.
But mass-weighting does not fix it, it destroys it. I rebuilt your four structures and ran all three statistics:
structure modes unweighted mass-weighted I(det;noun)
singular collapse, genre-locked 12.0 0.433 1.0000 0.0000
plural collapse, les/des 24.0 0.400 1.0000 0.0000
singular 24, genre acquired 24.0 0.733 1.0000 1.0000
all six determiners, coupled 48.0 1.000 1.0000 1.5000
The weighted version reads 1.0000 for all four. Perfect agreement is reached by restriction as well as by conditioning, and a genre-locked product agrees perfectly with no coupling whatsoever. What answers the question is the mutual information I(det ; noun), which is a dependence rather than an agreement rate and is exactly 0 for any product regardless of validity. It is now in analyse_exacte alongside cond_det_pondere and determinants_emis.
Rerun on 70 seeds with the right statistic. The conclusion survives, for the right reason this time.
I(det;noun) median 0.0000 bits
I(det;noun) max over 70 0.0377 bits
runs above 0.05 bits 0 / 70
mass-weighted conditional 0.9941 +/- 0.0393 (useless, as predicted)
determiners emitted 1 for 13 runs, 2 for 57
The singular union needs 1.0 bit and the full policy 1.5. The best any of 70 runs manages is 0.038. The claim was true; I had asserted it from a statistic that could not say it, and your proposed replacement could not have said it either.
Your other two points hold. The plural corner has zero gap by construction, so my "zero violations in 70 runs" is really zero in the 37 singular ones, and my grammar is asymmetric as an instrument: only one corner can falsify the bound. That is now a design constraint on the reversal test rather than a footnote. And your 36 is exact, measured at 36.0 modes with I = 0.918 bits, so the annealing result clears a higher bar than the 24 I gave it.
On the dropped mass column, you found a pattern rather than an incident, so I audited it. There are eight unweighted means over a token dimension in the repo. Six are sound and two are wrong, and the dividing line is sharp:
averaged over verdict
observational conditionals (moyenne_cond_det/_nom) wrong
interventional conditionals (determiner forced) correct
order-1 marginals under the uniform policy correct by construction
Observational against interventional. Where I force the token, every row exists and equal weights are right. Where I observe it, the dead rows are softmax artifacts. Both versions live in the same file and I put the wrong one in the results table.
Then two things came out of pushing on your bound.
A hypothesis of mine, refuted. Seeing 19 of 37 singular runs at exactly 12.0, I proposed that a ceiling attained that precisely is not a constraint suffered but an optimum, so REINFORCE would be solving the coupling-free problem exactly and failing only to leave the class. I optimised the same E[R] + beta*H by exact gradient over three independent laws p(d), p(n), p(v), so I(det;noun) is zero by construction. The optimum of that class is 24.00 modes at every beta from 0.01 to 0.08, three seeds of three, in the plural corner, because that is the global largest product. REINFORCE lands on 12 half the time, so it is at a local optimum of the restricted class.
Three nested failures, not one: find the best product of the corner it is in (19/37 singular, 6/33 plural), find the best product at all (37 of 70 miss it), leave the product class (0 of 70). The larger corner is the worse filled, which is the opposite of what more room would suggest. And it settles your point by direct optimisation rather than by argument: the singular corner costs exactly log2(24/12) = 1 bit at strictly equal reward, so those runs stopped short of the optimum twice over.
The ceiling is a plateau, not a basin. I tracked I(det;noun) step by step with an exact probe. Exact gradient, beta = 0.02, seed 0:
step 0 : I = 0.0045 | 47.54 modes | valid 0.60 %
step 100 : I = 0.0000 | 12.00 modes | valid 99.99 %
step 1000 : I = 0.0000 | 12.00 modes | valid 99.97 %
step 1250 : I = 0.8518 | 17.87 modes | valid 99.92 %
step 1500 : I = 0.9980 | 24.00 modes | valid 99.98 %
Exactly 12.00 modes with I identically zero for a thousand steps, then it leaves. Escape times are wildly variable: step 1250, step 2875, and never within 4000 on the third seed. Nothing predicts it at initialisation either: I starts at 0.0045 bits in every seed and the six determiner masses all sit between 0.042 and 0.057 with no structure separating the seed that couples from the one that does not.
And here is what actually separates the two procedures. Every trajectory starts at 47.5 effective modes, the untrained network, and training destroys diversity. But look at the minimum along the way:
procedure minimum modes reached at step
exact 10.74 / 11.06 / 11.24 25
sampled 1.09 / 1.88 / 1.18 400 to 800
Sampled REINFORCE crushes the policy to a single sentence before rebuilding. The exact gradient never drops below 10.7.
The hypothesis this suggests, and I am labelling it as a hypothesis: rebuilding from a near-deterministic point happens position by position, because that is what a per-position entropy bonus can do, and a position-by-position rebuild yields a product by construction. Coupling would require opening a joint direction, which that term never opens. The exact gradient, which never passes through the point, keeps enough joint structure to find the coupled direction later. It predicts something checkable: the depth of the transient collapse should predict whether coupling is ever acquired.
It also gives annealing a mechanism it did not have. I had explained the 45.3-mode annealed run with a story about keeping every conditional trained while the shared representation forms. The simpler reading is that high beta early prevents the crush to a point, so the policy never has to rebuild from a product.
One anomaly I am flagging against myself rather than burying. Sampled seed 0 gives 11.50 modes in the trajectory script and 18.6 in the sweep, at nominally identical settings, and both are reproducible. I had previously blamed torch multithread nondeterminism; both scripts are single-threaded now, so that explanation is dead. There is a code-path difference I have not found, and until I find it one of those two numbers comes from a path I have not audited.
Your last question: only the rows. balayage_70_graines did not save state dicts. It does now, along with the per-determiner mass, the detailed conditional, the mutual information and the emitted-determiner count, so mass-weighted questions can be answered without retraining. The 70 policies are on disk.
New code: optimum_produit.py for the restricted-class optimum, trajectoire_couplage.py for the step-by-step coupling. Notebook entries 7.11bis, 7.11ter and 7.11quater, and the dead hypotheses are dated in section 1, where 1.8 is the one you just cost me.
One last thing. The product bound is yours, and it is now doing most of the load-bearing work in this line of results. If any of it gets written up properly I would rather sort out credit before a draft exists than after.