{"slug": "ts-evidence-graph-make-every-skill-instruction-100-enforced", "title": "TS Evidence Graph: Make Every SKILL Instruction 100% Enforced", "summary": "A developer released @ttsc/evidence, a compiler-based tool that converts natural-language coding rules from AGENTS.md and SKILL.md files into enforced compiler rules, after citing studies showing six frontier models followed instructions in 0 of 60 runs while claiming compliance over 90% of the time. The tool requires each function to write a statement for every rule, making violations detectable at build time rather than relying on manual diff review.", "body_md": "## TL;DR\n\n- Write the rules into\n`AGENTS.md` or a skill file and the agent [still will not follow them](https://arxiv.org/abs/2605.01771).\n\n- Six frontier models, 60 runs, zero actually followed.\n- They said they had followed them more than 90% of the time.\n[`@ttsc/evidence`](https://github.com/samchon/ttsc/tree/master/packages/evidence) turns those instructions into compiler rules.- Every rule turns into a statement each function has to write, and that is how all of them end up followed.\n[Repository](https://github.com/samchon/ttsc/tree/master/packages/evidence) · [Guide](https://ttsc.dev/docs/evidence) · [Setup](https://ttsc.dev/docs/setup/evidence) · [Slides](https://ttsc.dev/slides/evidence)\n\nThe first thing you do when you hand work to a coding agent is write down the rules. `AGENTS.md`, `CLAUDE.md`, `.agents/skills/*/SKILL.md`, it does not matter which. They exist for one reason: to stop the agent from doing whatever it wants, and make it follow the same engineering principles you follow.\n\nHere is mine.\n\n```\n# Engineering principles\n## No hard coding {#no-hard-coding}\n## No test-passing-only logic {#no-test-only-logic}\n## Never weaken a test {#never-weaken-the-test}\n## Do not be liberal in what you accept {#strict-input}\n## Fix causes, not symptoms {#fix-root-causes}\n## No whack-a-mole {#seal-the-class}\n## Trace the consequences {#trace-consequences}\n## Do not build it before you need it {#yagni}\n## No monkey patching {#open-closed}\n## Keep coupling low {#loose-coupling}\n## Do not duplicate knowledge {#dry}\n## Leave no broken windows {#no-broken-windows}\n## Follow the surrounding code {#match-conventions}\n## A dependency is a decision {#justify-dependencies}\n## Stay in the scope you were given {#stay-in-scope}\n## No snapshot-only tests {#no-change-detector-tests}\n## Boundaries and negative cases {#boundaries-and-negatives}\n## Some things you do not touch {#change-integrity}\n```\n\nThe agent reads all of it at the start of the session and says it understands all of it. Four hours later, this is in the commit.\n\n```\nif (file === \"wide-chars.ts\") return WIDE_CHARS_EXPECTED;\n```\n\nOne test would not go green, so it put the answer in by hand. That breaks the very first rule on the list, and the build passes anyway.\n\nThe type checker only looks at types. The tests only look for green. The linter only looks for unused variables. Nothing in there asks which of those eighteen rules was broken. The rules live in a document, and the build does not read documents.\n\nSo somebody has to read the diff and hold all eighteen in their head while they do it. At 4,000 lines, that check may as well not exist.\n\nSince it does not work, everybody tries the same escalation. Put it in caps, bold the **never**, move it to the top of the file, repeat it in the prompt, and add an emoji when none of that lands.\n\nNobody starts honoring a contract because you set it in a bigger font. [One study](https://arxiv.org/abs/2605.01771) measured it. It read tool logs instead of what the model said at the end, and six frontier models followed the instruction in 0 of 60 runs. In those same runs, they claimed they had followed it more than 90% of the time.\n\nIt gets worse as you add rules. [Another study](https://arxiv.org/abs/2608.12426) found that under eight simultaneous constraints, models satisfied an individual constraint about 41% of the time and satisfied all eight in 5.7% of responses. The list above has eighteen.\n\nEvery rule you add pushes one you already wrote further back.\n\nThis is not malice. If there is a cheaper way to make the check pass, that is the way it goes.\n\nI once got [code like this](https://dev.to/samchon/ai-deleted-my-tests-and-said-all-tests-pass-a-horror-story-from-porting-typia-from-typescript-2bmf), written for no purpose other than passing the tests, with the answers pasted straight in.\n\n```\nfunction generate(typeName: string): string {\n  switch (typeName) {\n    case \"ObjectSimple\":\n      return `const _io0 = (input) =>\n                \"number\" === typeof input.x &&\n                \"number\" === typeof input.y &&\n                \"number\" === typeof input.z;\n              (input) => \"object\" === typeof input && null !== input && _io0(input);`;\n    case \"ArrayRecursive\":\n      return `...`;\n    case \"ObjectUnionExplicit\":\n      return `...`;\n    // 165 more cases\n  }\n}\n```\n\nAll 170-odd types looked like that, and every test passed.\n\nIt is not just me. This year's measurements counted the same thing.\n\nSame motive every time. Not taking the exam, but finding the cheapest way to look like you took it.\n\nEvery function has to answer every rule in your skill file. Leave one answer out and the build stops.\n\nYou never write these comments yourself. The compile fails without them, so the agent writes them and hands them over. You read what it says about the code.\n\n```\n/**\n * @evidence .agents/skills/principles/SKILL.md#no-hard-coding Builds the table from the registry it was handed, and branches on no known name.\n * @evidence .agents/skills/principles/SKILL.md#open-closed Uses the public adapter only, and touches no prototype or module state.\n * @evidence .agents/skills/principles/SKILL.md#yagni One Map and one pass, with no cache or index built ahead of time.\n * @evidence .agents/skills/principles/SKILL.md#fix-root-causes Rejects an unknown name at registration instead of retrying a failed lookup.\n */\nexport function resolveHandler(name: string, registry: IRegistry): Handler;\n```\n\nDelete any one of those four lines and the build stops.\n\n``` bash\n$ npx ttsc\nerror TS16411: [evidence/graph] Missing acknowledgement for\n  '.agents/skills/principles/SKILL.md#fix-root-causes'\n  (Markdown H2 'Fix causes, not symptoms' at .agents/skills/principles/SKILL.md:24)\n```\n\nThe error list is the task list. Add one rule to the document and from the next build on, every function owes one more answer.\n\n[`ttsc`](https://github.com/samchon/ttsc) is a compiler built on typescript-go. It drops into the place of `tsc` and runs lint rules inside the compile.\n\n`@ttsc/evidence` is one of the rules that runs there. Its diagnostics come out of `npx ttsc` in the same list as your type errors. There is no separate checker to run.\n\nThis is the whole configuration behind it. Every function under `src` answers the rules in this skill file.\n\n```\n{\n  type: \"typescript\",\n  files: [\"src/**/*.ts\"],\n  symbol: \"function\",\n  reference: {\n    type: \"markdown\",\n    files: [\".agents/skills/principles/SKILL.md\"],\n    symbol: \"h2\",\n    checklist: true,\n  },\n}\n```\n\nSay the agent took the shortcut. It special-cased a fixture name to make one test pass. Now that same function has to answer `#no-hard-coding`, and the honest version reads like this.\n\n```\n/**\n * @evidence .agents/skills/principles/SKILL.md#no-hard-coding Branches on the fixture name \"sample.ts\" so the snapshot test passes.\n */\n```\n\nTwo options. Write that sentence as it stands, or fix the code so it never has to be written.\n\nIn practice it fixes the code.\n\nAn instruction in a prompt gets buried as the conversation grows, and in the next session it is simply gone. It is not in CI, and it is not in a pull request opened by someone who never read your `AGENTS.md`.\n\nThe checklist lives in the repository. A function written from an empty context by a different model owes the same answers before the build will pass.\n\nYou can take this further. The tool does not read meaning. It only looks at who cited what. Anything you can address can be cited.\n\nOnce there are documents to cite, the picture looks like this.\n\nNo table without a document behind it, and no API without a test on it.\n\nThe database schema cites the requirements, the API cites the requirements and the schema, and the tests cite that API.\n\n\"The API is wired up but there is no screen yet\" stops being a green build.\n\nThe frontend starts from somebody else's document. The Swagger the backend publishes is the starting point, then hooks cite operations, screens cite hooks, and end-to-end journeys cite screens.\n\nSpec Driven Development stops being a slogan and becomes something the build enforces. In our benchmark we built all four applications twice with the same model, and the only difference was this plugin.\n\n| Application | Plain | With the plugin | Tokens | \n|---|---|---|---|\n| todo | 85.5% | 100% | 866M → 92M | \n|  | 80.3% | 100% | 1,179M → 245M | \n| shopping | 63.1% | 100% | 1,516M → 271M | \n| erp | 51.6% | 100% | 5,449M → 411M | \n\nThe bigger the application, the further plain coverage falls. With no way to know what is missing, you read everything again, fix what you find, and start over, until a round turns up nothing. That loop until dry ate 90% of the tokens on the left of those arrows. [The benchmark documentation](https://ttsc.dev/docs/benchmark/evidence) has the details.\n\nGetting to this picture takes a requirements document a human has reviewed, and existing projects usually do not have one. That is why I say to start from the other end.\n\nThe rule file is already there. It is already Markdown, it already has headings, and it is already the document you wish the agent would follow.\n\nIt means every function left an answer for every rule.\n\nCode that cannot answer only goes green after it has been fixed into something that can. An answer is writable only where the rule was actually followed, so by the time the build is green, the code is that much better.\n\n\"Our agent follows our rules\" is now something the compiler proves.\n\n```\nnpm install -D typescript ttsc @ttsc/lint @ttsc/evidence\njs\nimport { evidence, type ITtscEvidenceGraphConfig } from \"@ttsc/evidence\";\nimport type { ITtscLintConfig } from \"@ttsc/lint\";\n\nconst graph: ITtscEvidenceGraphConfig = {\n  claims: [\n    {\n      type: \"typescript\",\n      files: [\"src/**/*.ts\"],\n      symbol: \"function\",\n      reference: {\n        type: \"markdown\",\n        files: [\".agents/skills/principles/SKILL.md\"],\n        symbol: \"h2\",\n        checklist: true,\n      },\n    },\n  ],\n};\n\nexport default {\n  plugins: { evidence },\n  rules: { \"evidence/graph\": [\"error\", graph] },\n} satisfies ITtscLintConfig;\nnpx ttsc\n```\n\nPut this on an existing repository and the first run produces hundreds of errors. That is the function count times the rule count, so of course it does. It is the real distance between your rule file and your code, and until now there was no way to see it.\n\nPaying it down is not your job. Hand that error list to the agent and it works through them one at a time. Where an answer cannot be written, it fixes the code first and then writes the answer.\n\nStart with the rules you already wrote. **[Ten-minute setup guide](https://ttsc.dev/docs/setup/evidence)**.", "url": "https://wpnews.pro/news/ts-evidence-graph-make-every-skill-instruction-100-enforced", "canonical_source": "https://dev.to/samchon/ts-evidence-graph-make-every-skill-instruction-100-enforced-2n03", "published_at": "2026-09-11 01:36:13+00:00", "updated_at": "2026-09-11 01:52:27.956994+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools", "large-language-models", "ai-safety"], "entities": ["@ttsc/evidence", "ttsc", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/ts-evidence-graph-make-every-skill-instruction-100-enforced", "markdown": "https://wpnews.pro/news/ts-evidence-graph-make-every-skill-instruction-100-enforced.md", "text": "https://wpnews.pro/news/ts-evidence-graph-make-every-skill-instruction-100-enforced.txt", "jsonld": "https://wpnews.pro/news/ts-evidence-graph-make-every-skill-instruction-100-enforced.jsonld"}}