Skip to content

Commit ed320b5

Browse files
brabojclaude
andauthored
docs(decisions): hybrid is the delivery floor (#1920) (#1958)
* docs(decisions): hybrid is the delivery floor (#1920) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(decisions): cite ADR-052's probe figures from the rescore, and state one placement rule The probe figures came from the score.py rescore, not from the round-4 report the record cited, and only two of three trials read. Rule 2 now requires inlining only when breaking is silent and no tool enforces it, matching rule 3, the table and the diagram. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 26fff5f commit ed320b5

3 files changed

Lines changed: 132 additions & 0 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
---
2+
id: "052"
3+
status: Accepted
4+
date: 2026-10-17
5+
category: composition
6+
supersedes: []
7+
superseded_by: []
8+
---
9+
10+
# ADR-052: Hybrid is the delivery floor
11+
12+
## Context
13+
14+
A generated context file delivers each rule one of three ways: copied in
15+
(inline), named as a file to read (reference), or both, with the rules that
16+
matter copied in and the rest named (hybrid). The interview offers all
17+
three, and `agents.md` recommends hybrid without ruling reference out.
18+
19+
| Force | What it shows |
20+
| ----- | ------------- |
21+
| No loading mechanism | A referenced template is not loaded at startup, on relevance, or by any cue. It is read only when the agent decides to open it (#712) |
22+
| A consumer it failed | Under a reference-model file, a project's agent never opened the deferred templates across a session of git, testing and review work. A type-check gate that lived only there was missed and CI went red, and the defer list itself drifted unnoticed (#712) |
23+
| Adherence | In round 3 hybrid adhered to the project's conventions best of every arm: +21.6 pp against no file, where the short inline file read +11.1 pp (#1893) |
24+
| Security under a thin spec | In round 4, with a spec that states the contract and not the defences, hybrid scored highest of every arm on the judge's security and data-protection rows (`docs/audits/2026-10-17-round-4.md`). Rescored with the secret key the spec had omitted, two of its three trials read 0.82 and 1.00 on the security probes; the third was not measured (`rounds/2026-10-16-thin-sensitivity/score-py` in `braboj/tariff-runs`) |
25+
| A cost of length | Under a weaker model in round 4, every template file but the hand-written one lowered task success against no file |
26+
| A gap in the evidence | No round has run a reference-only arm, so the benchmark has not compared reference with hybrid directly |
27+
28+
## Decision
29+
30+
A generated context file delivers rules inline or hybrid, never by reference
31+
alone: a rule whose breaking is silent and that no tool enforces is inlined,
32+
and any other rule may stay a reference.
33+
34+
## Rationale
35+
36+
- A reference has no loading mechanism, so a rule that exists only as a
37+
reference is a rule the agent may never read; the consumer failure shows
38+
the cost lands where nothing catches it.
39+
- Placement by damage and enforcement keeps every rule an agent must not miss
40+
in context, while a rule whose breaking shows itself, or that a test,
41+
linter or CI step checks, can stay outside it and keep the file short.
42+
- Hybrid is the arm the benchmark reads best on adherence and on security, so
43+
making it the floor moves generation towards the measured result rather
44+
than away from it.
45+
- The direct comparison is missing, so the record names the round that
46+
supplies it and what result would reopen it.
47+
48+
## Design
49+
50+
![How one rule is placed: if breaking it is silent and no test, linter or CI step enforces it, it is inlined; if it fails visibly or a tool enforces it, it may be referenced. Inline and hybrid remain; pure reference is deprecated](../diagrams/delivery-model.png)
51+
52+
1. **The floor** — Generation MUST NOT produce a file that delivers its
53+
rules by reference alone. Inline and hybrid remain.
54+
2. **Inline the silent, unenforced rules** — A rule MUST be inlined when its
55+
breaking is silent, showing no error to the agent or the user, and no
56+
test, linter or CI step enforces it.
57+
3. **Reference the rest** — A rule whose breaking fails visibly, or that a
58+
test, linter or CI step enforces, MAY be referenced instead of inlined.
59+
4. **Where the rubric lives** — `agents.md` states the rubric, and the
60+
interview applies it; neither offers the reference model.
61+
5. **Length is a cost, not a cap** — Inlining SHOULD stop at the rules rule 2
62+
requires. This record sets no size limit.
63+
64+
| Breaking the rule... | Enforced by a tool | Not enforced by a tool |
65+
| -------------------- | ------------------ | ---------------------- |
66+
| fails visibly | MAY reference | MAY reference |
67+
| is silent | MAY reference | MUST inline |
68+
69+
## Alternatives considered
70+
71+
| Alternative | Why not |
72+
| ----------- | ------- |
73+
| Keep three models and recommend hybrid | Reference stays on offer, and the consumer failure is what it produces |
74+
| Inline everything | The weaker-model result shows that length costs; a project vendoring the templates duplicates them |
75+
| Allow reference delivered as a skill | A skill is loaded on demand from its description, which a plain reference is not, but no round has tested one; it is left to a later record |
76+
| Wait for the reference arm before deciding | The missing mechanism is known, and generating reference files meanwhile ships the failure it causes |
77+
78+
## Consequences
79+
80+
| Consequence | Where |
81+
| ----------- | ----- |
82+
| `agents.md` "Choosing a model" states the rubric and drops reference | #712 |
83+
| The interview stops offering the reference model | #712 |
84+
| Skills as a delivery layer are reconsidered against this floor | #414 |
85+
| Round 5 runs a reference-only arm beside hybrid. If it is no worse on adherence and on the judge's security and data-protection rows, this record is reopened | #1957 |
86+
| Whether inlined length needs a bound for weaker models stays open until more than one project and K = 3 measure it | — |
87+
88+
## Compatibility
89+
90+
A project whose context file uses the reference model keeps working: nothing
91+
it names is removed. Its next regeneration produces a hybrid file. The
92+
reference model is listed under `Deprecated` in the CHANGELOG with hybrid as
93+
its replacement, and is removed from the interview and `agents.md` in the
94+
release that implements this record.
95+
96+
## Security
97+
98+
Protects: a security rule whose breaking is silent, such as output escaping,
99+
a CSRF token, or a secret kept out of logs, is always in the agent's context,
100+
where a reference-only file could leave it unread.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<mxfile host="drawio">
2+
<diagram id="delivery-model" name="delivery-model">
3+
<mxGraphModel grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="1440" pageHeight="600" background="#FFFFFF" math="0" shadow="0">
4+
<root>
5+
<mxCell id="0" />
6+
<mxCell id="1" parent="0" />
7+
<mxCell id="t1" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=26;fontColor=#0F172A;fontStyle=1;" value="How a generated file delivers a rule" vertex="1"><mxGeometry x="30" y="18" width="1380" height="36" as="geometry" /></mxCell>
8+
<mxCell id="t2" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontFamily=Segoe UI;fontSize=13;fontColor=#64748B;" value="A rule must be inlined only when its breaking is silent and no tool enforces it; pure reference is no longer generated." vertex="1"><mxGeometry x="30" y="54" width="1380" height="24" as="geometry" /></mxCell>
9+
<mxCell id="g1" parent="1" style="rounded=1;arcSize=2;whiteSpace=wrap;html=1;fillColor=#F8FAFC;strokeColor=#CBD5E1;strokeWidth=1.5;align=left;verticalAlign=top;spacingLeft=16;spacingTop=10;fontFamily=Segoe UI;fontSize=14;fontColor=#334155;fontStyle=1;" value="Placing one rule" vertex="1"><mxGeometry x="30" y="100" width="1380" height="230" as="geometry" /></mxCell>
10+
<mxCell id="q" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#F1F5F9;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#475569;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;One rule&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#475569&#x27;&gt;from the template chain&lt;/span&gt;" vertex="1"><mxGeometry x="60" y="175" width="220" height="80" as="geometry" /></mxCell>
11+
<mxCell id="d" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#F1F5F9;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#475569;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;Is its breaking silent, and unenforced?&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#475569&#x27;&gt;no error shows, and no test, linter&lt;br&gt;or CI step checks it&lt;/span&gt;" vertex="1"><mxGeometry x="390" y="165" width="300" height="100" as="geometry" /></mxCell>
12+
<mxCell id="inl" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#FEF3C7;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#B45309;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;Inline it&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#92400E&#x27;&gt;MUST be copied into&lt;br&gt;the context file&lt;/span&gt;" vertex="1"><mxGeometry x="880" y="140" width="260" height="70" as="geometry" /></mxCell>
13+
<mxCell id="ref" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#F1F5F9;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#475569;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;May reference it&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#475569&#x27;&gt;named in the file, read only&lt;br&gt;when the agent opens it&lt;/span&gt;" vertex="1"><mxGeometry x="880" y="230" width="260" height="70" as="geometry" /></mxCell>
14+
<mxCell id="e1" parent="1" source="q" target="d" style="edgeStyle=orthogonalEdgeStyle;rounded=1;arcSize=16;html=1;jettySize=auto;strokeColor=#64748B;strokeWidth=2.0;endArrow=blockThin;endFill=1;endSize=5;fontFamily=Segoe UI;fontSize=11;fontColor=#475569;fontStyle=1;labelBackgroundColor=#F8FAFC;exitX=1;exitY=0.5;entryX=0;entryY=0.5;" value="" edge="1"><mxGeometry relative="1" as="geometry" /></mxCell>
15+
<mxCell id="e2" parent="1" source="d" target="inl" style="edgeStyle=orthogonalEdgeStyle;rounded=1;arcSize=16;html=1;jettySize=auto;strokeColor=#64748B;strokeWidth=2.0;endArrow=blockThin;endFill=1;endSize=5;fontFamily=Segoe UI;fontSize=11;fontColor=#475569;fontStyle=1;labelBackgroundColor=#F8FAFC;exitX=1;exitY=0.3;entryX=0;entryY=0.5;" value="both" edge="1"><mxGeometry relative="1" as="geometry" /></mxCell>
16+
<mxCell id="e3" parent="1" source="d" target="ref" style="edgeStyle=orthogonalEdgeStyle;rounded=1;arcSize=16;html=1;jettySize=auto;strokeColor=#64748B;strokeWidth=2.0;endArrow=blockThin;endFill=1;endSize=5;fontFamily=Segoe UI;fontSize=11;fontColor=#475569;fontStyle=1;labelBackgroundColor=#F8FAFC;exitX=1;exitY=0.7;entryX=0;entryY=0.5;" value="fails visibly, or a tool enforces it" edge="1"><mxGeometry relative="1" as="geometry" /></mxCell>
17+
<mxCell id="g2" parent="1" style="rounded=1;arcSize=2;whiteSpace=wrap;html=1;fillColor=#F8FAFC;strokeColor=#CBD5E1;strokeWidth=1.5;align=left;verticalAlign=top;spacingLeft=16;spacingTop=10;fontFamily=Segoe UI;fontSize=14;fontColor=#334155;fontStyle=1;" value="Delivery models" vertex="1"><mxGeometry x="30" y="350" width="1380" height="170" as="geometry" /></mxCell>
18+
<mxCell id="m1" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#FEF3C7;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#B45309;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;Inline&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#92400E&#x27;&gt;every rule copied in&lt;br&gt;for a project that does not vendor the templates&lt;/span&gt;" vertex="1"><mxGeometry x="80" y="405" width="360" height="85" as="geometry" /></mxCell>
19+
<mxCell id="m2" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#FEF3C7;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#B45309;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;Hybrid — the floor&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#92400E&#x27;&gt;silent, unenforced rules inline; the rest referenced&lt;br&gt;the least a generated file may do&lt;/span&gt;" vertex="1"><mxGeometry x="540" y="405" width="360" height="85" as="geometry" /></mxCell>
20+
<mxCell id="m3" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#FFE4E6;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#BE123C;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;Reference — deprecated&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#9F1239&#x27;&gt;rules only named, none in context&lt;br&gt;no longer generated; a file in use keeps working&lt;/span&gt;" vertex="1"><mxGeometry x="1000" y="405" width="360" height="85" as="geometry" /></mxCell>
21+
<mxCell id="lg-0s" parent="1" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;gradientColor=#FFFFFF;gradientDirection=north;strokeWidth=1.6;fillColor=#F1F5F9;strokeColor=#475569;" value="" vertex="1"><mxGeometry x="34" y="563" width="24" height="18" as="geometry" /></mxCell>
22+
<mxCell id="lg-0t" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=12;fontColor=#475569;" value="A step in placing a rule" vertex="1"><mxGeometry x="68" y="560" width="220" height="24" as="geometry" /></mxCell>
23+
<mxCell id="lg-1s" parent="1" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;gradientColor=#FFFFFF;gradientDirection=north;strokeWidth=1.6;fillColor=#FEF3C7;strokeColor=#B45309;" value="" vertex="1"><mxGeometry x="300" y="563" width="24" height="18" as="geometry" /></mxCell>
24+
<mxCell id="lg-1t" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=12;fontColor=#475569;" value="Delivered in the agent&#x27;s context" vertex="1"><mxGeometry x="334" y="560" width="250" height="24" as="geometry" /></mxCell>
25+
<mxCell id="lg-2s" parent="1" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;gradientColor=#FFFFFF;gradientDirection=north;strokeWidth=1.6;fillColor=#FFE4E6;strokeColor=#BE123C;" value="" vertex="1"><mxGeometry x="620" y="563" width="24" height="18" as="geometry" /></mxCell>
26+
<mxCell id="lg-2t" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=12;fontColor=#475569;" value="Deprecated" vertex="1"><mxGeometry x="654" y="560" width="140" height="24" as="geometry" /></mxCell>
27+
<mxCell id="lg-3s" parent="1" style="endArrow=blockThin;endFill=1;endSize=5;html=1;strokeColor=#64748B;strokeWidth=2.0;" edge="1"><mxGeometry relative="1" as="geometry"><mxPoint x="790" y="572" as="sourcePoint" /><mxPoint x="830" y="572" as="targetPoint" /></mxGeometry></mxCell>
28+
<mxCell id="lg-3t" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=12;fontColor=#475569;" value="The path a rule takes" vertex="1"><mxGeometry x="844" y="560" width="220" height="24" as="geometry" /></mxCell>
29+
</root>
30+
</mxGraphModel>
31+
</diagram>
32+
</mxfile>

‎docs/diagrams/delivery-model.png‎

365 KB
Loading

0 commit comments

Comments
 (0)