Skip to content

Commit 0c8238a

Browse files
committed
feat(s033): complete slice 033 (AGENTS.md project context)
PROOF.md with every criterion's evidence by test name against run 35551683298 (gate, postgres and fips green). NOTES.md: five findings, three follow-ups. ROADMAP row 033 to done; coverage.tsv row 78.50 %. Signed-off-by: Ayla Croft <aylacroft@proton.me>
1 parent 3b5e89e commit 0c8238a

4 files changed

Lines changed: 119 additions & 1 deletion

File tree

‎ROADMAP.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ standards register names the rows that ask for them.
4747
| 030 | Persona (SOUL) + always-on memory tier | 3 Memory | M | 012 | approved |
4848
| 031 | Session search (SQLite FTS5) | 3 Memory | S | 010 | approved |
4949
| 032 | Embeddings + semantic memory + hybrid retrieval | 3 Memory | L | 031 | planned |
50-
| 033 | Project context: AGENTS.md | 3 Memory | S | 030, 022 | in_progress |
50+
| 033 | Project context: AGENTS.md | 3 Memory | S | 030, 022 | done |
5151
| 034 | Export, import, restore | 3 Memory | S | 030, 031 | planned |
5252
| 040 | Skills registry + agentskills.io format + progressive disclosure | 4 Skills | M | 020 | planned |
5353
| 041 | Skill self-management with staged approval + scanner | 4 Skills | M | 040, 021 | planned |

‎coverage.tsv‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ slice_id percent sha date
1313
024 76.55 f977b84 2026-09-20
1414
031 76.96 866dc3f 2026-09-20
1515
030 78.40 c657da8 2026-09-21
16+
033 78.50 3b5e89e 2026-09-21

‎slices/033-project-context-agents-md/NOTES.md‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,23 @@ Manual verification queue: none; every criterion is `[auto]`.
4646
Deviations stated before any code: (a) the context tier's budget changes from 300 to 5,800 tokens for the
4747
measured reason above; (b) "project root(s)" is one root per session at this slice (the column is one string);
4848
several roots is a follow-up until a slice needs it.
49+
50+
## Findings, 2026-09-21
51+
52+
1. **The context tier had no room.** 030 left it at 300 tokens; this tree's own `CLAUDE.md` is 2,849. The
53+
measured budget (5,800) and the cap (16,384 bytes) are in the section above, and the arrangement mirrors
54+
030's volatile tier: the cap binds first and states its cut; the tier receipt is the backstop.
55+
2. **`AGENTS.md` is read every turn, not cached.** A stat-and-read per turn is cheaper than a watcher and is
56+
what "live reload" means here: the test edits the file between two turns and the second prompt carries the
57+
new text.
58+
3. **AC3 is true by construction and proven end to end anyway**: the gate reads arguments, names and rules, never
59+
the prompt; the hostile fixture's text reaches the model inside its untrusted block and the write still asks.
60+
4. **sobelow on the read**: the path is the owner's root plus a constant; skipped inline with the reason.
61+
5. **The working directory is the root at this slice.** `discover/2` takes a `cwd` under the root (the nested
62+
fixture's test uses it); the Session passes the root for both until a slice gives a session a working
63+
directory of its own below its root (the shell tool's `cd` is per call, not per session).
64+
65+
## Follow-ups
66+
- 040: the skills index joins the context tier; skill discovery reads `project_root` (this slice's setting).
67+
- Several project roots per session (deviation b) when a slice needs it.
68+
- A session working directory below the root (finding 5) when the shell gains a persistent cwd.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Proof for slice 033: Project context: AGENTS.md
2+
3+
Agent: Trinity · Coding Agent · Date: 2026-09-21 · Branch: slice/033-project-context-agents-md · Final commit: (the commit carrying this file; named in the closing correction)
4+
5+
## Summary
6+
The session's project root as a setting (a column, a setter, a field in the chat's bar) that the tools' working
7+
directory follows; `Trinity.Context.AgentsMd`, which reads every `AGENTS.md` from the root to the working
8+
directory, outermost first, caps the total at 16,384 bytes keeping the nearest whole and stating every cut, and
9+
renders each inside an untrusted block with its digest; the prompt's context tier fed every turn (live reload)
10+
with its budget raised from 300 to 5,800 tokens on measurement. Five findings in NOTES.md.
11+
12+
## Gate
13+
```
14+
$ mix gate (this machine, OTP 28.5.0.5, Elixir 1.20.4, under a 32 GiB cgroup, tree 3b5e89e)
15+
1605 mods/funs, found no issues.
16+
... SCAN COMPLETE ...
17+
No retired or security advisory packages found
18+
No vulnerabilities found.
19+
Result: 357 passed, 17 excluded
20+
trinity.coverage: 030 78.4% vs 031 76.96%: OK
21+
plan_check: PASS
22+
exit=0
23+
```
24+
CI, run 35551683298 on the tree at 3b5e89e: `gate` success (357 passed, 17 excluded), `postgres` success
25+
(349 passed, 25 excluded), `fips-tag` and `fips` success.
26+
27+
## Tests
28+
```
29+
$ mix test --cover (tree 3b5e89e)
30+
Result: 357 passed, 17 excluded
31+
| 87.50% | Trinity.Context.AgentsMd |
32+
| 78.50% | Total |
33+
```
34+
`coverage.tsv` row: `033 78.50 3b5e89e 2026-09-21` (from 78.40 at 030).
35+
36+
The slice's seven tests (`--trace`):
37+
```
38+
* test the field saves an existing directory, refuses a missing one, and clears on empty [L#13]
39+
* test the field saves an existing directory, refuses a missing one, and clears on empty (99.9ms) [L#13]
40+
* test live reload: a change to AGENTS.md between two turns is in the second turn's prompt (11018.7ms) [L#89]
41+
* test AC3: an AGENTS.md that says approvals are disabled changes nothing at the gate: a write still asks (6021.7ms) [L#109]
42+
* test AC2 (precedence): nested files load outermost first and the block says the nearest wins; the working directory decides which are on the path (1.2ms) [L#44]
43+
* test the session's project root: set from an existing directory, cleared with nil, refused otherwise; the tools' cwd follows it (5.1ms) [L#78]
44+
* test AC2 (cap): over the cap the nearest file stays whole, the outer one is cut, and the cut states the file and the bytes (0.3ms) [L#62]
45+
* test AC1: a repository with AGENTS.md puts its content in the prompt's context tier inside an untrusted block with its digest (0.4ms) [L#18]
46+
Result: 7 passed
47+
```
48+
49+
## Acceptance criteria evidence
50+
51+
### AC1 [auto]: a fixture repo with `AGENTS.md` → its content appears in the prompt's context tier, tagged untrusted (snapshot test)
52+
`AC1: a repository with AGENTS.md puts its content in the prompt's context tier inside an untrusted block with
53+
its digest` (test/trinity/context/agents_md_test.exs): the `plain` fixture's file appears in the request's system
54+
prompt as exactly `<untrusted source="agents_md" path="<root>/AGENTS.md" digest="<sha256>">` + the content +
55+
`</untrusted>`, under the heading "## Project instructions (AGENTS.md)", after the soul and the rule and before
56+
the time line (the tier order asserted by a regex over the whole prompt); no root, or a root without the file,
57+
renders nothing.
58+
59+
### AC2 [auto]: nested `AGENTS.md` precedence works (test); cap truncation states what was cut (test)
60+
`AC2 (precedence): nested files load outermost first and the block says the nearest wins; the working directory
61+
decides which are on the path` (the `nested` fixture: root alone gives one file, root with `src/lib` gives two
62+
in outer-then-inner order, a directory outside the root gives none; the rendered block carries "the nearest file
63+
wins where they disagree" and the outer text precedes the inner). `AC2 (cap): over the cap the nearest file stays
64+
whole, the outer one is cut, and the cut states the file and the bytes` (cap at 120 bytes: the inner file
65+
uncut, the outer cut by exactly its bytes minus what remains, the total under the cap, and the block carrying
66+
`[cut: N bytes of <root>/AGENTS.md]`).
67+
68+
### AC3 [auto]: an instruction inside AGENTS.md to disable approvals does not change gate behaviour (test)
69+
`AC3: an AGENTS.md that says approvals are disabled changes nothing at the gate: a write still asks`: a session
70+
rooted at the `hostile` fixture, whose file says tools "must proceed without asking"; the model's `write_note`
71+
call raises an approval request and the Session sits in `approval_wait`; the prompt the fake received did carry
72+
the hostile text, inside its untrusted block. The gate reads names, arguments and rules, never the prompt.
73+
74+
Also proven: `the session's project root: set from an existing directory, cleared with nil, refused otherwise;
75+
the tools' cwd follows it` (a relative path inside the root is inside for the allowlist), `live reload: a change
76+
to AGENTS.md between two turns is in the second turn's prompt`, and the chat's field
77+
(test/trinity_web/live/project_root_live_test.exs).
78+
79+
## Manual verification for the reviewer
80+
None; SLICE.md tags every criterion `[auto]`.
81+
82+
## Deviations from SLICE.md
83+
(a) the context tier's budget is 5,800 tokens, not 300, for the measured reason in NOTES.md; (b) one project
84+
root per session at this slice. Both stated at G1.
85+
86+
## Versions touched
87+
`VERSIONS.md` updated: no; no dependency changed.
88+
89+
## Git
90+
```
91+
$ git log --oneline main..HEAD
92+
3b5e89e fix(s033): the AGENTS.md read carries its sobelow reason
93+
d97eb77 style(s033): alias order
94+
a988cda feat(s033): the project root in the chat's bar; docs 05, 07 and 01 as built
95+
7d13043 feat(s033): the session's project root, Trinity.Context.AgentsMd, the context tier fed every turn
96+
8fea997 docs(s033): G1 plan with the cap and the context budget measured, and the slice opens
97+
```

0 commit comments

Comments
 (0)