|
| 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