Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
242 commits
Select commit Hold shift + click to select a range
97edb26
Implement cross-stack benchmarks program (phases 1-6, 8 functional)
multiarc Jul 21, 2026
e683db3
Repro scripts and docs
multiarc Jul 21, 2026
425295b
Add go executables into .gitignore
multiarc Jul 21, 2026
ae2c6fc
Add benchmark results
multiarc Jul 22, 2026
3f0c532
Temp
multiarc Jul 25, 2026
02405ba
Add benchmarks/dotnet cross-stack harness; publish 2026-07-25 report
multiarc Jul 25, 2026
6fa117e
Merge remote-tracking branch 'origin/main' into feature/benchmarks
multiarc Jul 25, 2026
9bd9e6f
Implement generator↔engine code-sharing program (phases 0–6)
multiarc Jul 26, 2026
c92e1d4
Restore PrecompiledGauntlet work destroyed by a reviewer git-checkout
multiarc Jul 26, 2026
77360f8
Phase 5 restoration audit: remove stale using left by the revert
multiarc Jul 26, 2026
8ae29af
Phase 3 restoration audit: fix the reconstructed fingerprint detail s…
multiarc Jul 26, 2026
187f577
Phase 6 restoration audit: build the D12.5 projection-equivalence corpus
multiarc Jul 26, 2026
45154fd
Phase 0 audit: tighten the gates, add the third seed, correct D4's fa…
multiarc Jul 26, 2026
8b53f41
Phase 2 audit: pin 7 rebuilt, 9 mutation gaps closed, WI5 recorded un…
multiarc Jul 26, 2026
8f9c1fe
Author phase 7 (shared test corpus) spec + plan; tighten a second sta…
multiarc Jul 26, 2026
20958b9
Phase 4 audit: fold the duplicate numeric table, kill 4 surviving mut…
multiarc Jul 26, 2026
8392282
Record all post-implementation open questions in the register
multiarc Jul 26, 2026
855caaf
Record the six post-implementation rulings (Q7.4, Q8.1-Q8.5)
multiarc Jul 26, 2026
c415943
Record Q7.1-Q7.3 rulings; phase 7 no longer touches Heddle.Performance
multiarc Jul 26, 2026
fedb483
Author phase 8 (post-implementation docs sweep) plan
multiarc Jul 26, 2026
d3a9465
Q8.3/Q8.4: fold the runtime onto the orphan cores; model [ExportExten…
multiarc Jul 26, 2026
121e10a
Phase 1 audit: real Release enforcement, name-independent pins, Q8.5 …
multiarc Jul 26, 2026
0ccfabc
Register Q8.13-Q8.17 from the phase 1 and phase 3 audits
multiarc Jul 26, 2026
5d6f308
Record rulings for Q8.8-Q8.17; correct the Q5.1 Name-removal overreach
multiarc Jul 26, 2026
daf7f91
Land Q8.1, Q8.2, Q8.11, Q8.12, Q8.16, Q8.20
multiarc Jul 26, 2026
29522a2
Record finding 10: the item metadata never worked from a real project
multiarc Jul 26, 2026
94774b7
Record rulings Q8.18, Q8.19, Q8.24-Q8.27; Q8.25 is a correction
multiarc Jul 26, 2026
b767965
Q8.25: make Name additive, not an override; Q8.27 #line path forms
multiarc Jul 26, 2026
bc8ac49
Record Q8.28-Q8.31 rulings; Q8.30 expands scope to runtime name search
multiarc Jul 26, 2026
47044b0
Q8.28-Q8.31: runtime name search, line-form in manifest, opted-out va…
multiarc Jul 26, 2026
9db1466
Register Q8.32-Q8.35 for ruling
multiarc Jul 26, 2026
3753dcc
Record the Q8.32-Q8.35 rulings
multiarc Jul 26, 2026
1f25e93
Q8.33 split the fallback carriers; Q8.32(b) end the silent name drop
multiarc Jul 26, 2026
dd13572
Rule Q8.37 (remove auto-loading in 2.1); close Q8.38 as not a question
multiarc Jul 26, 2026
558216c
Q8.35: fold the schema-tracks-breakage rule into the window policy
multiarc Jul 26, 2026
9e64967
Q8.9: map documentation authority as D10; Q8.10: reject phase 8's D9
multiarc Jul 26, 2026
8f71c37
Consolidate Q8.32/Q8.33 into the 2.1 record; file Q8.39 (window confl…
multiarc Jul 26, 2026
aa7ff23
Ignore .claude/ (agent worktrees, local session state)
multiarc Jul 26, 2026
25f6df9
Land Q8.17 and Q8.19; close Q8.14 as not implementable
multiarc Jul 26, 2026
c6ce35d
Q8.32 subset A: validate everything once, after configuration
multiarc Jul 26, 2026
0357076
Thin the Q&A register to one final answer per entry
multiarc Jul 26, 2026
94a4e8f
Rule Q8.39 (2.1 is a window) and Q8.40 (E9 governs inputs)
multiarc Jul 26, 2026
d7ddd00
Schedule the two unowned docs residues as phase 8 WI16 and WI17
multiarc Jul 26, 2026
ac1d0b4
Revert the corpus relocation; test inputs stay in TestTemplate
multiarc Jul 26, 2026
1b0ee64
Revise phase-7 D1: the corpus does not move
multiarc Jul 26, 2026
218c5ab
Add the comment rule to coding standards; strip citations I wrote
multiarc Jul 26, 2026
0def74a
Phase 7 stage 0: the sharing mechanism, without moving the corpus
multiarc Jul 26, 2026
59f5df1
Pin line endings for the relocated artifacts folder
multiarc Jul 26, 2026
7ede055
Comments exist only when the code cannot carry the meaning
multiarc Jul 26, 2026
c64ed77
Consolidate the comment requirements into one rule set (C1-C8)
multiarc Jul 26, 2026
97c0159
Sweep comments across the repo to the C1-C8 rules
multiarc Jul 26, 2026
f039b55
Comment sweep, pass two: the files pass one left behind
multiarc Jul 26, 2026
e1c29f1
Rule Q8.42-Q8.44: share what is shared, leave the rest alone
multiarc Jul 26, 2026
2266f29
Comment sweep, pass three: the last dense files
multiarc Jul 26, 2026
d4b0683
Finish the citation sweep: the 17 files the swarm could not
multiarc Jul 26, 2026
4aebf47
Simplify comments: delete what earns nothing, shorten the rest
multiarc Jul 26, 2026
40984cd
Remove assembly auto-loading; extensions come from explicit registration
multiarc Jul 26, 2026
9fd0988
Record the auto-loading removal and rewrite the docs that promised di…
multiarc Jul 26, 2026
b051b96
Give the marker tier a member: the corpus gains an unresolvable-funct…
multiarc Jul 26, 2026
211f424
Close phase 7 on the Q8.42 ruling and correct the duplicates claim in…
multiarc Jul 26, 2026
a46d2d1
Extend the comment rules to build files and to emitted doc comments
multiarc Jul 26, 2026
e6fd56f
State that the comment rules cover build files and emitted comments
multiarc Jul 26, 2026
257091c
Correct the four false claims in native-expressions.md
multiarc Jul 26, 2026
0003eb6
Correct the imprecise normative claims in native-expressions and prec…
multiarc Jul 26, 2026
cab2865
Document every shipped diagnostic id, and gate that it stays documented
multiarc Jul 26, 2026
6639f6f
Retract the 1.x-manifest rejection claim and the verbatim-doc coupling
multiarc Jul 26, 2026
72cf2c1
Narrow documentation authority in the ledger, and mark what is verified
multiarc Jul 26, 2026
661a99e
Carry the 2.1 breaks into the CHANGELOG, and fix two contradicted claims
multiarc Jul 26, 2026
7ca7080
Gate the documented option surface and the extension's defaults
multiarc Jul 26, 2026
2ada519
Gate documented member mentions against the public-API golden
multiarc Jul 26, 2026
97528cd
Gate documentation links and line citations
multiarc Jul 26, 2026
cd316a8
Land the documentation-currency rule and close phase 8
multiarc Jul 26, 2026
80b4958
Track the agent-instruction drafts; ignore BenchmarkDotNet's output d…
multiarc Jul 26, 2026
5e50dbc
Re-ratify the codegen sample's golden for the emitted doc comments
multiarc Jul 26, 2026
519a30f
Close the gate holes the completion review demonstrated
multiarc Jul 26, 2026
cd3a665
Fix the registration race an adversarial review reproduced
multiarc Jul 26, 2026
7fd1999
Fix the single-file and load-order defects, and the false claims arou…
multiarc Jul 26, 2026
66c5a60
Record the independent review and what it says about the pins
multiarc Jul 26, 2026
01922e5
Give the C# tier metadata it can actually reach, and stable diagnostics
multiarc Jul 27, 2026
e818ac1
Make observation notice an unload followed by a load
multiarc Jul 27, 2026
7997562
Honour the benchmark project's change-nothing ruling; pin the no-load…
multiarc Jul 27, 2026
d2beb20
Report an import cycle instead of dying on it
multiarc Jul 27, 2026
570cf84
Stop the generated tier rejecting templates the engine renders
multiarc Jul 27, 2026
ecaca87
Guard the parse walk's depth; record the second review
multiarc Jul 27, 2026
50832db
Bound parse depth by count, in both tiers
multiarc Jul 27, 2026
2576bc2
Fix what the third review found, including two regressions of mine
multiarc Jul 27, 2026
1b64d10
Fix the fold's uint conversion and set the depth bound where it can fire
multiarc Jul 27, 2026
25b2554
Pin the depth limit; close two more fold divergences
multiarc Jul 27, 2026
0f9ba46
Measure the depth bound in the configuration it ships in
multiarc Jul 27, 2026
cb4c426
Delete a guard that never fired, and stop claiming member paths are free
multiarc Jul 27, 2026
13c7172
Bind a null-safe hop's receiver once instead of copying it
multiarc Jul 27, 2026
8a30aed
Bound how many @<< imports one parse expands
multiarc Jul 27, 2026
8010e2a
Decide shifts, bitwise operators and constant conditionals in the fold
multiarc Jul 27, 2026
be7b4c1
Give the compile-item catch-all an id and a message that says something
multiarc Jul 27, 2026
1f3ef70
Report an unreadable @<< import instead of throwing out of the parse
multiarc Jul 27, 2026
6b2b876
Identify an import the way the reader resolves it
multiarc Jul 27, 2026
49d17e9
Drop the C#-tier preparse cache when model assemblies go
multiarc Jul 27, 2026
4ad3283
Take one parse's import state off the shared settings object
multiarc Jul 27, 2026
66b86df
Close the P3 findings: two unpinned properties, three stale texts, on…
multiarc Jul 27, 2026
e46d0b6
Stop emitting ?. on a type that has no nullable form
multiarc Jul 28, 2026
d034dda
Give a parse begun inside an import reader its own state
multiarc Jul 28, 2026
0db6222
Close the confirmed divergences: null-safe chains, cache epoch, unmea…
multiarc Jul 29, 2026
726031b
Fix the regression the last commit introduced, and six defects found …
multiarc Jul 29, 2026
f872b79
Close the three the eighth cycle left open
multiarc Jul 29, 2026
31e618d
Wrap embedded C# too, widen three guards that were narrower than thei…
multiarc Jul 29, 2026
4680907
Key the path memo on symbols, and refuse three more names the consume…
multiarc Jul 29, 2026
4f299ce
Answer the type-nameability question once instead of enumerating it
multiarc Jul 29, 2026
6d013eb
Mirror the engine's dynamic-slot rule instead of guessing it
multiarc Jul 29, 2026
27dd357
Type a dynamic definition body by the value its caller passes
multiarc Jul 30, 2026
e14e862
Tell "the emitter cannot say" apart from "the engine has no type"
multiarc Jul 30, 2026
c1b20dd
Read a prop before the model inside a native expression
multiarc Jul 30, 2026
2664141
Carry the caller's layout into caller content, and its text into a chain
multiarc Jul 30, 2026
669eef8
Ask an extension what it accepts instead of guessing from the value
multiarc Jul 30, 2026
2d3fab6
Ask the shared type facts what the runtime accepts
multiarc Jul 30, 2026
f990a9c
Give a region body its host's model, not just its host's props
multiarc Jul 30, 2026
74d1055
Share one region body where the engine compiles one
multiarc Jul 31, 2026
b2270e2
Ask a region what its declared model resolves to
multiarc Jul 31, 2026
540c096
Ask whether generated code may name a bound extension, and a namespace
multiarc Jul 31, 2026
ec613c2
Ask each tier's own question about a name, a path and a constant
multiarc Aug 1, 2026
703567d
Make the findings register class-keyed and record cycle 23
multiarc Aug 1, 2026
7de93b7
Execute two parser guards that no test reached
multiarc Aug 1, 2026
08872ff
Carry a constant's type difference, and ask the compiler four questio…
multiarc Aug 1, 2026
672ab71
Record cycle 24, and close the class the register said to enumerate
multiarc Aug 1, 2026
cde2a29
Read a @using body as the C# directive it is, so an alias binds a type
multiarc Aug 1, 2026
0f2a3c3
Record the alias work, and a Release-only failure Debug never showed
multiarc Aug 1, 2026
fd26220
Pin the model-type guard and the culture the goldens render under; ad…
multiarc Aug 1, 2026
801dfde
Parse a probe tree the way the compilation it joins was parsed
multiarc Aug 1, 2026
2cc2893
Fail a test run that executes no tests
multiarc Aug 1, 2026
02409b5
Point every regression check at a filter property that exists
multiarc Aug 1, 2026
6655879
Rank an export call on the argument's own type, and type a list body …
multiarc Aug 1, 2026
377f5b2
Let an alias outrank the index, give three rounding built-ins their i…
multiarc Aug 1, 2026
51f68be
Merge branch 'worktree-agent-aeb12ca01625f9796' into feature/benchmarks
multiarc Aug 1, 2026
ec10b0e
Merge branch 'worktree-agent-aa8fae1a8ed1fcfd9' into feature/benchmarks
multiarc Aug 1, 2026
f455e81
Close nine parked defects, and stop the protocol from protecting them
multiarc Aug 1, 2026
34cb3ee
Give `this` an operand arm, hand the built-in binder a symbol, and st…
multiarc Aug 1, 2026
409efdc
Record the three fixes, and fail on a test case dropped as a duplicate
multiarc Aug 1, 2026
fac16a1
Re-test the last two parked reasons; one holds, one does not
multiarc Aug 1, 2026
cc5cd43
Fix register
multiarc Aug 1, 2026
d7d32a7
Improve documentation, fix tests and add missing tests
multiarc Aug 1, 2026
7c79435
Drive a boxed non-string through the value path as bytes, and correct…
multiarc Aug 1, 2026
f8ebbbd
Drain the compile channel at build time, under the engine's own diagn…
multiarc Aug 1, 2026
b001e28
Refuse a model the template cannot accept, and stop precompiling past…
multiarc Aug 1, 2026
4826644
Separate every publish from the build that feeds it, and gate the con…
multiarc Aug 1, 2026
1decce3
Give the sweeps a cardinality guard, and let every CI leg see a dropp…
multiarc Aug 1, 2026
6a6a10e
Retire .NET 6, and move the netstandard2.0 pins onto the 8.x line
multiarc Aug 1, 2026
6ad7773
Stop spelling the modern-BCL guard after a framework that is gone
multiarc Aug 1, 2026
690cb06
Keep the collectible-context probes off the framework that has no suc…
multiarc Aug 1, 2026
2595ba3
Move the suites to xUnit v3 on Microsoft Testing Platform
multiarc Aug 1, 2026
1685493
Take the whole tree to zero build warnings, and write down how it sta…
multiarc Aug 1, 2026
63389e6
Re-measure the four open alias findings, and keep the one that was wrong
multiarc Aug 1, 2026
2ffabf7
Rebuild the .NET benchmark leg from scratch, and delete the project i…
multiarc Aug 1, 2026
2439fa9
Budget the measurement per engine, and buy .NET the term it never sam…
multiarc Aug 1, 2026
44b8b53
Resize every leg to the per-engine budget, and correct E13's own arit…
multiarc Aug 1, 2026
745ee9d
Windows version
multiarc Aug 2, 2026
ef57474
Cleanup and alignment
multiarc Aug 2, 2026
c74c3b3
New bench
multiarc Aug 2, 2026
72bebc6
Stop timing the harness, and stop the runtime tier re-transcoding its…
multiarc Aug 2, 2026
e262908
Take every test project green on every target framework
multiarc Aug 2, 2026
ac8e16f
Ship one generator per Roslyn generation, and give it a .NET Framewor…
multiarc Aug 2, 2026
95ffe90
Refuse constant division by zero at compile time, on both tiers, unde…
multiarc Aug 2, 2026
848be06
Rename the variant solution folder out of the project name it collide…
multiarc Aug 2, 2026
0f91751
Close the shift, ternary and coalesce gaps in the operator table
multiarc Aug 2, 2026
67c2238
Adapters instead of bails: RuntimeOperators closes mixed equality and…
multiarc Aug 2, 2026
841f8ab
Table corrections: flip what the engine always refuses, emit what C# …
multiarc Aug 2, 2026
569ead7
Type identity for the shared table: same-enum and reference shapes no…
multiarc Aug 2, 2026
5ed9647
Constants speak the engine's type, user operators emit through adapters
multiarc Aug 2, 2026
80d477e
Structural emissions: paths, indexers and call dispatch reach everywhere
multiarc Aug 2, 2026
68cd0c5
Lexer errors reach the error list instead of the console
multiarc Aug 2, 2026
2a698c4
ModelType item metadata types a template from the csproj
multiarc Aug 2, 2026
14348d4
The engine's refusals fire at build: eight ids forwarded, sentences e…
multiarc Aug 2, 2026
fdef2ac
Three known defects close, three skips lift
multiarc Aug 3, 2026
23acc0d
Retire stale defect prose the fixes left behind
multiarc Aug 3, 2026
a773a50
HtmlEncodedRenderer stops paying for text that needs no encoding
multiarc Aug 3, 2026
5cd5840
Documentation says what the code does again
multiarc Aug 3, 2026
720af95
The first protocol-machine run is published, and it is a different en…
multiarc Aug 4, 2026
935d27b
The JS launcher can no longer mistake a null exit code for success
multiarc Aug 4, 2026
cc4d9be
The sink rows say what their numbers mean where the numbers appear
multiarc Aug 7, 2026
8c1ac3a
The Node pin is the major line, and the strictness finally points at it
multiarc Aug 7, 2026
7674be0
The CPython pin follows the Node ruling onto its minor line
multiarc Aug 7, 2026
3e90634
The re-issued run is on every pin, and the JS verdict is real
multiarc Aug 8, 2026
7a22c91
The layout idiom is proven at benchmark scale before any template tru…
multiarc Aug 8, 2026
247aba9
The composed page finally is one, and the fragments learned four shapes
multiarc Aug 8, 2026
6ce15fc
The corpus now carries a whole page, and the fixtures travel with it
multiarc Aug 8, 2026
77fb757
The templates speak only the native tier, and the emitter covers the …
multiarc Aug 8, 2026
658bb54
The fragment model forgot how to typeset, and the templates picked it up
multiarc Aug 8, 2026
bc62902
The floors stop pre-typesetting too, and the rule becomes the law E21
multiarc Aug 8, 2026
e79939b
Every word the page speaks now lives in a template
multiarc Aug 8, 2026
f371ac7
Five model twins forget their scripts and remember only their data
multiarc Aug 8, 2026
5d2160f
Fifteen engines learn the whole page, and every gate in six languages…
multiarc Aug 8, 2026
df35ca4
The specs catch up with the ports, and E23 writes the landing down
multiarc Aug 8, 2026
5c19c62
The Heddle tree keeps only what runs at the top, and Linux skips net48
multiarc Aug 8, 2026
7fb6842
Every engine keeps only what runs at the top, and E24 makes it law
multiarc Aug 8, 2026
4a51e87
The emitter learns the step-back four, and the encoded pair joins the…
multiarc Aug 8, 2026
a625989
The last odd name falls in line: home.heddle becomes composed-page.he…
multiarc Aug 8, 2026
f2c4d82
Go learns the two-track shape the other fifteen already keep
multiarc Aug 8, 2026
c469126
Five samples is the floor, and only .NET was under it
multiarc Aug 8, 2026
c7ac36e
Two programs close their books: the decisions stay, the plans go to h…
multiarc Aug 8, 2026
b6ea3bd
The drafts drop their suffixes: Claude's rules go live, refreshed aga…
multiarc Aug 8, 2026
6d62e0f
What the rename left behind: the refreshed rule text catches up with …
multiarc Aug 8, 2026
b53b1a8
HED7031's reason becomes pinnable, and the probe wrapper learns the e…
multiarc Aug 8, 2026
5d5c6f3
Embedded C# becomes a compiled fragment in the engine's own namespace…
multiarc Aug 8, 2026
77e5211
A computed @partial name evaluates once at static init the way the en…
multiarc Aug 9, 2026
71ba510
The typing decisions step out of the emitter's walk into a pure modul…
multiarc Aug 9, 2026
31ac70e
Every refusal names its class and plans queue ahead of it: the value …
multiarc Aug 9, 2026
27ce5c7
One hidden member no longer costs the file: the node escapes to the e…
multiarc Aug 9, 2026
cd4d625
The functions the build cannot see now bind themselves, once, at firs…
multiarc Aug 9, 2026
803bc02
A template that names no model now says so, and the registry stops se…
multiarc Aug 9, 2026
92c6dbc
One declaration now reaches all three tiers: the build learns which a…
multiarc Aug 9, 2026
d09a232
Both tiers stop writing their own ladder, and one of them was wrong a…
multiarc Aug 9, 2026
17aef41
Open generics were never the build's wall: the engine serves no such …
multiarc Aug 9, 2026
75ff555
The table was predicting what the extensions already say, and one row…
multiarc Aug 9, 2026
ee17852
The build can now ask an extension what its hook does, and only from …
multiarc Aug 9, 2026
49810cf
Shadow mode says GO: the probe answers, the table agrees with it, and…
multiarc Aug 9, 2026
c28cb68
Four arms become one: the emitter stops knowing extension names and s…
multiarc Aug 9, 2026
2beea1a
The docs catch up with thirteen stages: the coverage story is rewritt…
multiarc Aug 9, 2026
f2f9ba7
The encoding a body-hosting bind carries is pinned on its own, where …
multiarc Aug 9, 2026
589e17a
Nine hand-kept numbers come out of CI, and what a suite contains is n…
multiarc Aug 9, 2026
93bd88e
The gate against hardcoded extension names starts reading the whole a…
multiarc Aug 9, 2026
afba2c0
The engine stops being the assembly with the right name and becomes t…
multiarc Aug 9, 2026
4356dbd
The hook probe goes, and the one thing it actually found stays behind…
multiarc Aug 9, 2026
66fcbba
The extensions get to answer for themselves: a seam that runs the rea…
multiarc Aug 9, 2026
2904d69
The extensions stop being predicted and start being run: custom bodie…
multiarc Aug 9, 2026
48593fb
The refusals left standing get pinned, and the type-agnostic body's p…
multiarc Aug 9, 2026
485010c
The slot projection stops being reimplemented and starts being bound,…
multiarc Aug 9, 2026
44219fd
The definition invocation joins the seam, and its carriers move to th…
multiarc Aug 9, 2026
992a990
The build gains a switch for observing the real engine, and an id for…
multiarc Aug 9, 2026
795a4f7
The testing rule learns what re-running a suite costs, and says to ke…
multiarc Aug 9, 2026
5ad2d8d
The observe cache moves back under obj, where a hand-imported targets…
multiarc Aug 9, 2026
fa36eac
The build stops guessing a hook's typing and reads it off a real engi…
multiarc Aug 9, 2026
c58993e
Twenty ledger rows stop waiting to be deleted: the measurement says t…
multiarc Aug 9, 2026
76290ab
The build stops refusing definition overrides: the parser had already…
multiarc Aug 9, 2026
515c00f
The corpus grows a tier for the fallback that costs one call site, an…
multiarc Aug 9, 2026
78dc63d
Every refusal category is audited against its own construction sites,…
multiarc Aug 9, 2026
58dc417
The published pages and the specs catch up with a build that runs the…
multiarc Aug 9, 2026
dd2fceb
The slot projection and the child template become roles an extension …
multiarc Aug 9, 2026
362199c
The partial stops being reimplemented and starts being run: the child…
multiarc Aug 9, 2026
18d7bb1
Five verdicts about the slot projection go back to the hook that make…
multiarc Aug 9, 2026
80945df
The slot projection opens its own door: the three things @out reads s…
multiarc Aug 9, 2026
c1edcfd
The chain stops being carriage and starts being a sequence: the build…
multiarc Aug 9, 2026
d3b64a1
The body that compiles to nothing installs nothing: the build reaches…
multiarc Aug 10, 2026
3a4cf81
A hook that named no model named the dynamic one: the late accessor r…
multiarc Aug 10, 2026
654959b
The sixteen names go and the reference assembly stops being a wall: a…
multiarc Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 18 additions & 0 deletions .claude/rules/api-compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
paths:
- "src/Heddle/**/*.cs"
- "src/Heddle.Generator/**/*.cs"
---

# API design and compatibility

Details: [coding-standards.md § API](../../docs/spec/common/coding-standards.md#api-design-and-compatibility), [breaking-windows.md](../../docs/spec/common/breaking-windows.md). Anchored in the .NET Framework Design Guidelines.

- Additive by default: new extensions, opt-in options, overloads. Existing templates and hosts compile and render byte-identically.
- Breaking changes land only in a ratified breaking window (D2), each with a migration note. Candidates go to the register in breaking-windows.md, not into code.
- Every new `TemplateOptions` property goes into the copy constructor (and `Equals`/`GetHashCode` when it keys identity) — missed before (`ProvideLanguageFeatures`); the completeness test enforces this.
- Public API additions carry XML docs + same-change updates to the affected published docs pages (`language-reference.md`, `custom-extensions.md`, `built-in-extensions.md`, `csharp-api.md`).
- Extend via the sanctioned seams (`[ExtensionName]` registry, options, function registry, output profiles, publish/read channel, resolver, encoder) — don't invent parallel mechanisms or new seams for single-implementation internals.
- The generator names no extension: no compare against a built-in name in any form, no `"Heddle.Extensions."` type literal, no `"Heddle"` assembly-name compare, no name-keyed table. Read the binder, the attributes, or the hook. `ExtensionAgnosticismTests` gates it over every file compiled into `Heddle.Generator.dll` — linked shared source included, via an embedded compile-input manifest — by Roslyn syntax walk rather than regex, so `string.Equals`, `case`, `is`, collection lookups and default parameter values are all caught, and by reading static string tables back by value. It is vocabulary-free, so a third-party name is caught too. Every declared row carries a `Why` ending in `permanent` or `retires in Stage N`.
- The generator never predicts a compile-time hook either: `PrecompiledRuntime.Init` constructs the extension in the consumer's assembly and runs its real `InitStart`/`CompleteInit`, so a bodied, hook-overriding, `[Prop]`-declaring or `[BranchRole]` custom extension precompiles in a default build. Where a hook's typing is unresolvable the body is emitted type-agnostically over `PrecompiledLateAccessor`, never refused. A call the seam cannot serve costs **that call site** (`PrecompiledRuntime.SiteFallback`, `[PrecompileUnsupported]`/`HED7033`), not the template — reach for a `Refusal` only where the whole file must go.
- Extension instances are shared across concurrent renders: no mutable per-render state on them; per-render state lives in the `Scope` lineage.
18 changes: 18 additions & 0 deletions .claude/rules/coding-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
paths:
- "**/*.cs"
---

# Coding style

Authority order: (1) surrounding code in the file, (2) [coding-standards.md](../../docs/spec/common/coding-standards.md), (3) `.editorconfig` (editor guidance only, not a gate).

- Block-scoped namespaces (`namespace X { … }`) — not file-scoped, even in new files.
- Allman braces predominantly — match the file. Braceless single-statement guards for early returns are idiomatic; multi-line/nested bodies always braced.
- `var` when the type is apparent; explicit types otherwise and for built-ins.
- Naming: `_camelCase` private instance fields; `PascalCase` private static readonly; `I`-prefixed interfaces; extension classes `<Name>Extension` with `[ExtensionName("name")]`.
- Existing quirks (space before parameter list, space after cast) are deliberate — do not "fix" them.
- Comments follow C1–C8: default to none; write one only when the code cannot carry the meaning; never cite specs, plans, findings, or reviews in code comments (C4). XML doc comments on public API; regression tests carry a doc comment explaining the pinned scenario.
- 4-space indent, UTF-8, final newline, ~120-column wrap.
- Never mass-reformat or run whole-file IDE cleanups; diffs contain only the lines the change needs. The established style is the maintainer's deliberate choice — consistency beats modernization.
- `src/Heddle.Language/generated/` is generated (ANTLR) — never hand-edited; grammar change = `.g4` edit → regen → commit both.
17 changes: 17 additions & 0 deletions .claude/rules/errors-diagnostics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
paths:
- "src/Heddle/**/*.cs"
- "src/Heddle.Generator/**/*.cs"
- "src/Heddle.Language*/**/*.cs"
---

# Errors and diagnostics

Details: [coding-standards.md § errors](../../docs/spec/common/coding-standards.md#error-handling-and-diagnostics), [cross-cutting-decisions.md D1 + registry](../../docs/spec/common/cross-cutting-decisions.md).

- Compile-path problems are collected, not thrown: positioned `HeddleCompileError`/`HeddleCompileWarning` on the compile result, so template authors see all problems at once. The public API never surfaces raw exceptions for template mistakes.
- Host-programming errors throw at public API entry points (`ArgumentNullException` etc.).
- Every new diagnostic claims a stable `HED####` ID from the registry (feature-area blocks, D1) **in the same change**; IDs are never reused or renumbered.
- An ID whose condition becomes unreachable is **retired in place**, not deleted: the `HeddleDiagnosticIds` constant, the `HeddleDiagnosticCatalog` row, the registry row and a mention in the page the registry names as owner all stay, and the registry row says what stopped firing, why, and what replaced it (often nothing). `DiagnosticIdTests` gates all four; deleting any would free the number for a later, different fault.
- Messages name the construct, point at the remedy, and carry the template position.
- Security-sensitive failures never degrade to execution: a sandbox violation is a compile error, full stop.
16 changes: 16 additions & 0 deletions .claude/rules/performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
paths:
- "src/Heddle/**/*.cs"
- "benchmarks/dotnet/**"
---

# Performance (render path is hot)

Details: [coding-standards.md § performance](../../docs/spec/common/coding-standards.md#performance-rules-the-render-path-is-hot).

- No new per-render allocations. `Scope` stays a `readonly struct` passed by `in`; optional per-render state is lazily created.
- Reflection at compile time only; render time executes pre-compiled delegates and direct calls.
- `[MethodImpl(AggressiveInlining)]` only on tiny, provably-hot transforms — with a benchmark justifying it.
- Perf claims are proven by BenchmarkDotNet (`benchmarks/dotnet`), never asserted. Hot-path changes run affected benchmarks before/after on the same machine: allocated bytes must not increase; mean must stay within reported error. Intentional trade-offs need maintainer ratification.
- Compile-time cost is "compile once, render many" — moderate compile-path allocation is fine, but startup/precompilation paths get measured too.
- No JIT-rescue assumptions for escaping allocations (D7).
15 changes: 15 additions & 0 deletions .claude/rules/spec-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
paths:
- "docs/spec/**"
---

# Spec and decision workflow

Details: [spec-conventions.md](../../docs/spec/common/spec-conventions.md), [cross-cutting-decisions.md](../../docs/spec/common/cross-cutting-decisions.md) (which also carries the condensed release and program records).

- Specs live under `docs/spec/`, indexed from `docs/spec/README.md` (update the index in the same change); they are contributor material, never published (D9).
- Plan = what/why (ratified input); spec = exactly how. A finished spec has **no open questions** — every point is a closed decision with evidence, or a most-reversible default plus a named revisit trigger.
- Implementation follows the owning plan's declared item order (D5): assume 1..N−1 merged; never depend on later items.
- Changing an earlier recorded decision goes through the amendment mechanism (evidence → maintainer ratification → implemented by the amending effort); earlier spec text is never silently retrofitted. The accumulated E1–E28 ledger is closed — new amendments are recorded as dated notes in the owning spec (see cross-cutting-decisions.md § Cross-spec amendments ledger).
- Balanced-mode principle precedence on conflicts: correctness/back-compat → sandbox security → simplicity → measured hot-path performance → abstraction/extensibility. DRY consolidates knowledge (rule of three); YAGNI cuts presumptive features, never tests/benchmarks/docs.
- Writing style: sentence-case headings, en/em dashes, relative links only, cite `path` + member name over bare line numbers.
22 changes: 22 additions & 0 deletions .claude/rules/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
paths:
- "src/*Tests*/**"
- "src/TestCorpus/**"
- "samples/**"
---

# Testing

Details: [testing-standards.md](../../docs/spec/common/testing-standards.md) — normative; this is the short form.

- Loop: write the spec's tests failing first → implement to green → run the gate → fix forward. Goldens/baselines/spec tables change only with maintainer review, never to silence a red test.
- Gate (one combined run): `dotnet build -c Release` → `dotnet test --project src/Heddle.Tests/Heddle.Tests.csproj` (all TFMs, serially; both Debug and Release when `#if DEBUG` arms are touched) → no diff under `src/Heddle.Language/generated/` (unless the spec licenses a grammar change) → benchmarks when a hot path is touched → `npm run docs:build` when docs pages changed.
- xUnit v3 on MTP: `dotnet test` needs `--project`/`--solution` (directory form is rejected); filters are MTP syntax after `--` (`--filter-method` etc.); a filter matching nothing exits 8; CI legs run through `.github/scripts/dotnet-test-guarded.sh <project>`, which passes `--fail-skips on`.
- **Run a suite once and keep the whole output.** These suites take minutes; re-running one to see a detail you piped away is the single most expensive habit available. Always `2>&1 | tee` (or redirect) the full run to a file, then read that file — grep it for failures, open the failing case, count tests, whatever is needed. Never pipe a run through `tail`/`grep` as the only sink, and never re-run a suite to answer a question the first run already contained. Redirect per suite so runs stay separable, and prefer one combined script that captures every suite in a single pass over four separate invocations.
- **No test-count floors.** `--minimum-expected-tests` was tried on nine CI legs and withdrawn: it is satisfied by editing a digit, it names nothing when it reddens, it drifted (one commit raised `dotnet.yml` and left `lsp.yml`, and that leg then tolerated a six-test regression for four commits), and it fails a leg for the wrong reason whenever a test is legitimately quarantined. What a suite CONTAINS is gated inside the suite: `src/<Suite>/test-classes.txt`, one line per fact-declaring class, set-equality asserted by that suite's `TestClassInventoryTests` — a red gate names the class. Deliberately the same shape as corpus membership below.
- Fixtures: `.heddle` + sibling golden under `src/Heddle.Tests/TestTemplate`; every new golden/fixture directory is LF-pinned in `.gitattributes` **in the same change**.
- Negative/security tests assert positioned `HED*` diagnostics (ID + position) and prove the construct never executes.
- Descriptive PascalCase sentence test names; assert with context (`Assert.True(result.Success, result.ToString())`); tests are exempt from DRY.
- Concurrency: any state shareable across renders ships a parallel-render isolation test.
- Precompiled tier: fallback to dynamic is byte-identical, so an unpinned test proves nothing about the tier it claims to test. End-to-end tests pin the tier (`PrecompiledMismatchPolicy.Strict` + fallback sentinel); expected fallbacks are declared only via `FallbackGuard.Expect` / `DifferentialHarness.ExpectDegrade`; quarantine guarded fixtures with an owning-item `Explicit = true` (reported *not run*, so it survives `--fail-skips`), never weaken them.
- Test-input single-sourcing: a template shape verified by more than one tier exists once, in the shared corpus, with declared (total) intent — duplicate copies drift silently and break the differential premise. Membership is gated by set equality — never a count or floor (a floor once hid 15 templates silently dropping out).
29 changes: 28 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,42 @@
# output — failing on Windows while Linux (LF everywhere) passes. Pin every such root to LF so the
# byte comparison holds identically on both platforms regardless of the developer's autocrlf setting.
# All files under these roots are text (verified: no binaries). New golden/fixture roots MUST be
# added here in the same change that introduces them — see docs/spec/common/testing-standards.md.
# added here in the same change that introduces them.
#
# eol=lf pins line endings and says nothing about byte-order marks; the two are independent, and a
# BOM drift can pass every eol=lf check there is. Templates carrying a deliberate UTF-8 BOM declare
# it in src/TestCorpus/CorpusIntent.cs, gated by CorpusIntentGateTests.
samples/**/golden/** text eol=lf
src/Heddle.Tests/TestTemplate/** text eol=lf
src/Heddle.Tests/TestOutput/** text eol=lf
src/Heddle.Tests/Streaming/** text eol=lf
src/Heddle.Generator.Tests/Snapshots/** text eol=lf
src/Heddle.Generator.IntegrationTests/Fixtures/** text eol=lf
src/Heddle.LanguageServices.Tests/Corpus/** text eol=lf
src/Heddle.Demo.Wasm/contract-fixtures/** text eol=lf

# The per-suite test-class inventories are read line by line and compared as a set on both platforms.
# Reading normalises CRLF, but pinning them keeps the diff a reviewer sees identical everywhere.
src/*/test-classes.txt text eol=lf

# Golden oracle corpus: the *.golden.html files intentionally end WITHOUT a trailing newline and must
# round-trip byte-exact on every platform, so they are pinned -text (no smudging at all) rather than
# eol=lf. The JSON sidecars are ordinary LF text.
benchmarks/dotnet/GoldenCorpus/*.golden.html -text
benchmarks/dotnet/GoldenCorpus/*.verify.json text eol=lf
benchmarks/dotnet/GoldenCorpus/manifest.json text eol=lf
# Exported model fixtures are hash-recorded in the manifest like the goldens; LF text.
benchmarks/dotnet/GoldenCorpus/fixtures/** text eol=lf

# Rust benchmark harness: composed-page fragment data must round-trip byte-exact (-text); template
# files are ordinary LF text (the harness erases their line endings, but LF keeps diffs clean).
benchmarks/rust/templates/** text eol=lf

# Python benchmark harness: template files are committed LF on every platform — Mako passes a literal
# \r\n in a template file through into rendered output, so LF-pinning keeps checked-in bytes equal to
# authored bytes.
benchmarks/python/templates/** text eol=lf

# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
Expand Down
38 changes: 38 additions & 0 deletions .github/scripts/dotnet-test-guarded.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Runs one test project under Microsoft.Testing.Platform, with the two guards that are worth having.
#
# Usage: dotnet-test-guarded.sh <project> [extra dotnet test args...]
#
# `--fail-skips on` turns a skipped test into a failed one. A skip is a test that stopped testing, and
# CI is the wrong place to find out quietly; the repository's protocol for a known-failing test is
# `[Fact(Explicit = true)]`, which is reported as NOT RUN rather than skipped and so survives this.
#
# Exit 8 -- a filter matched nothing, or discovery failed -- stays called out by name, because a stale
# filter that runs nothing used to pass. It is the platform's own signal, not a number anyone maintains.
#
# What this script no longer does is carry a per-suite `--minimum-expected-tests` floor. Nine of them
# were maintained by hand across two workflows and they failed at their own job: one commit added six
# tests, raised the floor in one workflow and left the other, and that leg then tolerated a six-test
# regression in silence for four commits. A floor is satisfied by editing a digit, it names nothing
# when it reddens, and it fails a leg for the wrong reason whenever a test is legitimately quarantined.
# Suite membership is gated instead by the checked-in test-class inventories (src/<Suite>/test-classes.txt,
# asserted by set equality inside each suite), which name the class that appeared or vanished.

set -uo pipefail

if [ "$#" -lt 1 ]; then
echo "usage: $0 <project> [extra args...]" >&2
exit 64
fi

project=$1
shift 1

dotnet test --project "$project" "$@" -- --fail-skips on
status=$?

if [ "$status" -eq 8 ]; then
echo "::error::Zero tests ran in ${project} -- a filter matched nothing, or discovery failed."
fi

exit "$status"
16 changes: 10 additions & 6 deletions .github/workflows/dco.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
# Verifies that every commit in a pull request carries a matching
# "Signed-off-by" trailer (Developer Certificate of Origin). This produces a
# required status check ("DCO / dco") that branch protection can enforce.
# Verifies that every commit in a pull request carries a matching "Signed-off-by"
# trailer (Developer Certificate of Origin).
#
# Alternative: install the DCO GitHub App (https://github.com/apps/dco) which
# provides the same check with zero maintenance. If you do, you can delete this
# workflow and require the app's "DCO" check instead.
# Two roles:
# - a required status check ("DCO / dco") that branch protection enforces on PRs
# - via workflow_call, the gate the PR-sourced deploy jobs depend on, so a beta package
# never ships from unsigned commits
#
# Releases from main are deliberately NOT gated: they are the maintainer's own, and a tag
# push carries no pull request to check.

name: DCO

on:
pull_request:
branches: [ "main" ]
workflow_call:

permissions:
contents: read
Expand Down
Loading
Loading