diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.084aec95.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.084aec95.jsonl new file mode 100644 index 00000000..534c8b3b --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.084aec95.jsonl @@ -0,0 +1 @@ +{"id":"en-a84648fd","kind":"enactment","at":"2026-10-26T21:47:57.933Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"6ef2867","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"two slots that answer one question agree\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f3779918.jsonl: pass batched (23.7 s) and alone (23.3 s)"},"2":{"result":"done","evidence":"one condition in answersAgree made && false; diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f3779918.jsonl; confirmed by node --test on the test's own AssertionError (actual pass)"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/check.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f3779918.jsonl: pass batched (23.7 s), refutation witnessed, and alone (23.4 s)"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.08e84854.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.08e84854.jsonl new file mode 100644 index 00000000..bf4b4844 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.08e84854.jsonl @@ -0,0 +1 @@ +{"id":"d-875e34b1","kind":"decision","at":"2026-10-26T23:36:18.910Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b78ee04","dirty":true,"chose":"after the TypeScript, Rust and Go parser migrations land: (1) one store of per-file facts with kinds that every reading queries, entrance rules and mirrors among them; (2) scope binding inside a file through locals queries; (3) a per-commit semantic index (SCIP) generated in CI as the cross-file reference layer; (4) parallel cold parsing on worker threads; in that order","over":["build them alongside the migrations, which touch the same core files"],"because":"the layered code model: syntax facts everywhere, binding derived from them, the language server and a batch index only where a question needs truth, runtime and history beside them, every reading a query over one store and every fact carrying its provenance; the fact store first removes the last per-reading readers (entrances, mirrors) and is what the rest builds on","human":"do them after the language-level migrations land","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.0d80aca2.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.0d80aca2.jsonl new file mode 100644 index 00000000..2cd369c9 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.0d80aca2.jsonl @@ -0,0 +1 @@ +{"id":"en-e2779679","kind":"enactment","at":"2026-10-26T23:18:58.904Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c30c378","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant (the three guide bullets) --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f0be580a.jsonl: pass batched (27.4 s) and each alone"},"2":{"result":"done","evidence":"one edit of docs/plugins.md each: the server agrees row dropped; the manifest example's pluginApi set to 2; start from python made go; each diff read before its refute"},"3":{"result":"done","evidence":"three refutations red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f0be580a.jsonl; each confirmed by node --test on plugin-docs.test.ts's own AssertionError"},"4":{"result":"done","evidence":"cmp of docs/plugins.md against the copy taken before the breaks printed nothing after each restore"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f0be580a.jsonl: 3 pass batched (23.8 s), refutation witnessed on each, and alone"},"6":{"result":"skipped","because":"every red came from its break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.29774f42.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.29774f42.jsonl new file mode 100644 index 00000000..b26a71e1 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.29774f42.jsonl @@ -0,0 +1,4 @@ +{"id":"d-9d919dd8","kind":"decision","at":"2026-10-27T21:08:59.765Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"766fba1","dirty":true,"chose":"the dead-end alarm and the journal it reads serve an agent that wants to work helpfully: they guard against what such an agent does by accident (a defect recorded with no file, a remedy that fails in another worktree, a false alarm, a crash, a slow orient), not against an agent choosing what to record to silence them","over":["an alarm no agent can silence by what it records"],"because":"the owner, on the blind review of 766fba1 finding four ways an agent could silence the alarm by its records","human":"the car doesn't need to be uncrashable, it just needs to help an agent that wants to work helpfully deliver that work","cites":["d-a5c35add"],"binding":"none: this session owns no active work order"} +{"id":"en-103589c3","kind":"enactment","at":"2026-10-27T21:09:13.773Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"766fba1","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"deviated","because":"the two misread bullets were new, so before the breaks their tests ran green in the whole syntax-trees.test.ts file (30 pass), not run --each; run --each came after"},"2":{"result":"done","evidence":"five breaks, each one exact replacement asserted to match once: no #not-parent-type? evaluation, misread kept from erring trees, an unknown predicate passed over, no misread written, the TypeScript exemption dropped"},"3":{"result":"done","evidence":"each red in syntax-trees.test.ts on its own assertion, named in its refuted: line, re-run against the file directly before each refute"},"4":{"result":"done","evidence":"each file restored from a copy taken before the break, filecmp byte for byte"},"5":{"result":"done","evidence":"run --invariant over the six touched bullets --each: batched pass, 6 alone, 6 pass, in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a16160ab.jsonl"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} +{"id":"d-aeacd05b","kind":"decision","at":"2026-10-27T21:45:36.971Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"766fba1","dirty":true,"chose":"the test of a reading's work bound runs under a 20 s budget","over":["shrinking its texts below the bounds it holds"],"because":"it must parse past each bound to show it holds, about 2 s of parsing in one process, which a loaded machine stretched past the unit suite's 8 s ceiling in a run beside another worktree's suite","binding":"none: this session owns no active work order"} +{"id":"en-33b9774f","kind":"enactment","at":"2026-10-27T21:53:49.561Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"766fba1","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant over the nine store bullets --each before the breaks: batched pass, 9 alone, 8 pass; the work bound's test failed alone past the 8 s ceiling under another worktree's load, then was rebuilt lighter, given a 20 s budget (d-aeacd05b), and its breaks staged again"},"2":{"result":"done","evidence":"16 breaks in r8/refute-r10.py, each one exact replacement asserted to match once; a parse bound removed first stayed green, since the query's bound caught the same text, so the test was rebuilt on two texts each past one bound alone"},"3":{"result":"done","evidence":"each red in syntax-trees.test.ts on its own assertion, named in its refuted: line; the green one under the old test was not recorded as a refutation"},"4":{"result":"done","evidence":"each file restored from a copy taken before the break, filecmp byte for byte"},"5":{"result":"done","evidence":"run --invariant over the nine bullets --each after: batched pass, 9 alone, 9 pass"},"6":{"result":"done","evidence":"the parse bound's break that stayed green was no refutation and recorded none; the rebuilt test went red under it"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.3d5871cb.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.3d5871cb.jsonl new file mode 100644 index 00000000..91e95e45 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.3d5871cb.jsonl @@ -0,0 +1,3 @@ +{"id":"df-7ac38ee4","kind":"defect","at":"2026-10-26T18:37:35.720Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"what":"Python's source slot reads nothing from a from-import split across lines: PY_FROM in plugins/python/python-source.ts matches only to the end of the first line, so from x import (\\n a,\\n b\\n) adds no name and, where a file imports a module only that way, no edge; mass and the economy's closure (src/economy/closure.ts) under-count Python reach, while python-scope.ts, the interfaces slot, reads the same import whole","evidence":"both slots run on main 1aef204 over 'from store.secrets import (\\n SECRET_COLUMNS,\\n seal,\\n)': source slot [] , interfaces slot the whole list; PostHog has 19,524 such imports of 139,146 top-level from-imports (14%) in 9,363 of 23,517 Python files; Python's check.json holds no multi-line import, so the imports duty passed","files":[],"class":"parse-gap","introduced":"8ec766c","caught":"review","binding":"none: this session owns no active work order"} +{"id":"x-adaa7243","kind":"experiment","at":"2026-10-26T18:37:50.597Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"expectation":"A Python plugin that supplies a tree-sitter parser and queries for imports and items, with the core deriving every Python syntax slot from them, reads what today's regex slots read and more, within the hook latency budget, and an outside author can supply one for a language of their own","context":["plugins/python/python-source.ts","plugins/python/python-scope.ts","src/plugins/languages.ts","df-7ac38ee4"],"actions":[{"id":"x-adaa7243.a1","text":"build on branch tree-sitter-pilot: web-tree-sitter 0.27.1 started once per process, a plugin's treeSitter parser loaded on first use, Python's source, declares, topLevel and interfaces slots derived from two queries"},{"id":"x-adaa7243.a2","text":"diff the derived slots against main's regex slots, imports and declarations, over Coherence's and PostHog's Python files, and classify every difference by reading the source"},{"id":"x-adaa7243.a3","text":"time the parser start and a cold edit hook on a PostHog Python file, and whole-PostHog mass, against main"},{"id":"x-adaa7243.a4","text":"three blind authors each write a Swift plugin from the branch's published docs alone, through the parser path, and plugin check grades each"}],"criteria":[{"id":"x-adaa7243.c1","text":"c1: every classified difference is one the regex slot got wrong; any difference the regex slot got right fails this"},{"id":"x-adaa7243.c2","text":"c2: the derived imports read the multi-line from-imports df-7ac38ee4 names, in Python's check.json and over PostHog"},{"id":"x-adaa7243.c3","text":"c3: a cold PreToolUse and PostToolUse on a PostHog Python file each stay under the 3 s latency budget"},{"id":"x-adaa7243.c4","text":"c4: whole-PostHog mass takes at most twice main's time on the same machine, measured alone"},{"id":"x-adaa7243.c5","text":"c5: at least 2 of 3 blind Swift plugins pass plugin check's mass and imports duties"}],"binding":"none: this session owns no active work order"} +{"id":"d-60863cd3","kind":"decision","at":"2026-10-26T18:59:45.696Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"chose":"the parser's freed-tree guard parses 400 times a 35 KB Python text no query matches, with a 20 s budget","over":["a count under the cliff, which a leak passes","a unit test held to the 8 s ceiling, which cannot reach the cliff"],"because":"with tree.delete() dropped, web-tree-sitter 0.27 aborts the process at parse #326 of that text after 5.2 s on this machine (the old harness crashed an adopter the same way at #638 of 80 KB); freed, 330 parses take 5.4 s, so a guard that can go red must pay about 6.5 s, twice the slowest seen is about 13 s, and 20 s matches the budgets on the other language-runtime tests (d-23f7f8eb, d-467bd43d)","cites":["d-23f7f8eb","d-467bd43d"],"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.3ec42a6a.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.3ec42a6a.jsonl new file mode 100644 index 00000000..80459eb1 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.3ec42a6a.jsonl @@ -0,0 +1,7 @@ +{"id":"df-7c50adfe","kind":"defect","at":"2026-10-26T22:43:39.265Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"8d78643","dirty":true,"what":"the parse store follows a symbolic link and deletes every file in its target: rewrite (src/plugins/syntax-trees.ts) removes every entry of .coherence/parses// but its own store file, and flush appends there, without checking the folder is a real folder inside the project, so a repository that commits .coherence/parses/python as a link to ~/.ssh has the warm-up a session start or a prompt launches empty ~/.ssh","evidence":"blind review of tree-sitter-pilot 8d78643, probe1.ts: a victim folder holding id_rsa and notes.txt was left holding only the store file; shipped in the GitHub prerelease v1.11.0-beta.0, deleted on the owner's word","files":[],"class":"path-identity","introduced":"a63081e","caught":"review","binding":"none: this session owns no active work order"} +{"id":"d-ce0f1a9b","kind":"decision","at":"2026-10-26T22:43:45.459Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"8d78643","dirty":true,"classifies":{"of":"df-7c50adfe","introduced":"46d80e0"},"chose":"classify df-7c50adfe: introduced 46d80e0","over":[],"because":"the parse store, rewrite and flush among it, came in 46d80e0; a63081e was the module form, named by mistake","cites":["df-7c50adfe"],"binding":"none: this session owns no active work order"} +{"id":"en-9520b38a","kind":"enactment","at":"2026-10-26T22:50:30.536Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"8d78643","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"the parse store never reaches past the project's own folders\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl: pass batched (27.7 s) and alone (25.2 s)"},"2":{"result":"done","evidence":"one line, safe() returning true first; diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl; confirmed by node --test on the test's own AssertionError (a link on the store's path keeps no parses)"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/syntax-trees-fix.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl: pass batched (27.6 s), refutation witnessed, and alone (27.0 s)"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} +{"id":"rs-7c3e9963","kind":"resolution","at":"2026-10-26T22:50:31.215Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"8d78643","dirty":true,"of":"df-7c50adfe","because":"the store refuses a link or a file anywhere from .coherence down to its folder, reads and appends through no link (O_NOFOLLOW), creates its temporary file exclusively, removes only its own files by name and only regular files, reads only files signed with a machine key kept in the user's Coherence folder, refuses a plugin name that could step out, and one warm-up runs at a time under a lock; sweep: every rmSync, unlinkSync and rmdirSync in src and plugins read: the store's rewrite was the one that enumerated a folder and removed broadly; vocabulary-state removes only its own tmp names; the rest remove single named files, which removes a link and never its target. Left as it was: other writers under .coherence (journal, runs, server files) still write through a folder a repository commits as a link, an older and wider exposure than this defect","guard":"src/plugins/the parse store never reaches past the project's own folders","binding":"none: this session owns no active work order"} +{"id":"en-69e91d38","kind":"enactment","at":"2026-10-26T22:54:54.152Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"8d78643","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"a whole-module import reaches a reference name only where the importer spells it\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl: pass batched (24.4 s) and alone (24.0 s)"},"2":{"result":"done","evidence":"one condition in referenceRelations made || true; diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl; confirmed by node --test on reference.test.ts's own AssertionError"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/check-fix.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl: pass batched (24.7 s), refutation witnessed, and alone (24.3 s)"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} +{"id":"en-f097ab4c","kind":"enactment","at":"2026-10-26T22:59:25.169Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"8d78643","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"a plugin is never failed by a duty newer than its interface\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl: pass batched (27.2 s) and alone (27.5 s)"},"2":{"result":"done","evidence":"one condition in notHeld made || true; diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl; confirmed by node --test on reference.test.ts's own AssertionError"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/check-fix2.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl: pass batched (32.1 s), refutation witnessed, and alone (27.6 s)"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} +{"id":"en-1722ac7a","kind":"enactment","at":"2026-10-26T23:03:10.875Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"8d78643","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"a TypeScript re-export is an import of what it re-exports\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl: pass batched (25.3 s) and alone (26.1 s)"},"2":{"result":"done","evidence":"the two re-export loops made to read nothing; diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl; confirmed by node --test on typescript-reexports.test.ts's own AssertionError"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/typescript-source.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl: pass batched (27.1 s), refutation witnessed, and alone (27.9 s)"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.460b3d9d.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.460b3d9d.jsonl new file mode 100644 index 00000000..5f379d24 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.460b3d9d.jsonl @@ -0,0 +1,5 @@ +{"id":"rs-79da06fc","kind":"resolution","at":"2026-10-26T19:12:33.004Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"of":"df-7ac38ee4","because":"Python is read through a tree-sitter parser and python.scm (x-adaa7243), every reading of its text derived from one parse, so a from-import read whole wherever its names fall; the core refuses a hand-written reader beside a parser. Sweep: every bundled plugin's hand-written import reader run over its language's multi-line import form on main 1aef204: TypeScript's import { a, b } from across lines, Rust's use a::{ b, c } across lines, Go's import ( ... ) block, each read whole; no sibling found. PostHog's Python, old readers against the parser: 79,294 imports spanning lines and 8,581 inside blocks now read, 223 names read out of comments and strings gone","guard":"src/plugins/a parser reads a statement whole","binding":"none: this session owns no active work order"} +{"id":"en-808c4cd1","kind":"enactment","at":"2026-10-26T19:12:39.513Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"command resolved df-*","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-7ac38ee4 recorded with --class parse-gap --introduced 8ec766c --caught review"},"2":{"result":"done","evidence":"searched every bundled plugin's hand-written import reader over its language's multi-line import form on main 1aef204 (TypeScript import { a, b } across lines, Rust use a::{ b, c } across lines, Go import ( ... )): each read whole, no sibling; Python's other two readers (topLevel, interfaces.importLists) replaced by the same parse"},"3":{"result":"done","evidence":"src/plugins/a parser reads a statement whole, beside src/plugins/a language read through a parser has one reader of its text"},"4":{"result":"done","evidence":"refutation red then witnessed in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.714383b1.jsonl (source slot made to read imports one line at a time, the class's shape)"},"5":{"result":"done","evidence":"rs-79da06fc; spec --check 0 problems"}},"binding":"none: this session owns no active work order"} +{"id":"en-11a540d6","kind":"enactment","at":"2026-10-26T19:48:36.772Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"a project's parses are kept between processes\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.d1efbd7e.jsonl: pass batched (23.5 s) and alone (23.8 s)"},"2":{"result":"done","evidence":"one line, ParseStore.get returning undefined for every key; the diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.d1efbd7e.jsonl; confirmed by node --test --test-name-pattern on the test's own AssertionError (a later process parses only its first few texts and the one that changed)"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/syntax-trees.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.d1efbd7e.jsonl: pass batched (24.3 s), refutation witnessed, and alone (24.2 s)"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} +{"id":"xc-d04dfb9b","kind":"close","at":"2026-10-26T19:55:56.163Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"of":"x-adaa7243","results":{"x-adaa7243.a1":"pass","x-adaa7243.a2":"pass","x-adaa7243.a3":"pass","x-adaa7243.a4":"pass","x-adaa7243.c1":"pass","x-adaa7243.c2":"pass","x-adaa7243.c3":"fail","x-adaa7243.c4":"fail","x-adaa7243.c5":"pass"},"outcome":"failure","binding":"none: this session owns no active work order"} +{"id":"c-38a1baae","kind":"conjecture","at":"2026-10-26T19:55:56.408Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"observation":"x-adaa7243, read after closing: c3 failed only because main's own cold PreToolUse on PostHog is 14.1 s (the pilot's 14.6 s); c4 failed as built (mass 14.8 s against 3.2 s, WebAssembly parsing about 11 MB/s), and kept parses with a session-start pre-read, built after at the owner's direction, bring it to 3.4 s, post-hoc. All three blind Swift authors ($49.39) passed every duty through the parser path, and all three met the missing module form of resolve: import Store names a SwiftPM target, the interface resolves one file, and each invented a different one-file rule (the file declaring the most names used; the file named after the target else the first; Store.swift else the first)","couldBe":["the instrument is wrong","resolve gains a module form, a target's whole folder, so an import of a module joins every file of it and no plugin invents a rule","the one-file rules are harmless: a component interface joins folders, and every rule picks a file inside the right one"],"discriminatedBy":"a Swift fixture where Api imports Store and uses only names declared in a file the one-file rules do not pick: whether mass and the economy's closure reach that file under each author's plugin","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.466e3838.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.466e3838.jsonl new file mode 100644 index 00000000..31f3abf3 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.466e3838.jsonl @@ -0,0 +1 @@ +{"id":"en-4efa655b","kind":"enactment","at":"2026-10-26T23:07:57.894Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e187366","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"command classify","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-7c50adfe recorded with --class path-identity --caught review, its origin corrected to 46d80e0 by classify (d-ce0f1a9b)"},"2":{"result":"done","evidence":"every rmSync, unlinkSync and rmdirSync in src and plugins read: the store's rewrite alone enumerated a folder and removed broadly; vocabulary-state removes only its own tmp names; the rest remove single named files; writers under .coherence through a committed link left as an older, wider exposure, said in rs-7c3e9963"},"3":{"result":"done","evidence":"src/plugins/the parse store never reaches past the project's own folders"},"4":{"result":"done","evidence":"refutation red then witnessed in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl (the path check made to pass whatever lies on the path)"},"5":{"result":"done","evidence":"rs-7c3e9963; spec --check 0 problems"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.546f6100.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.546f6100.jsonl new file mode 100644 index 00000000..d219ba9d --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.546f6100.jsonl @@ -0,0 +1,7 @@ +{"id":"df-42f25182","kind":"defect","at":"2026-10-27T00:58:43.155Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"3a49cd3","dirty":true,"what":"the TSX grammar reads an old-style cast (x) in a .ts file as a JSX tag that swallows every later declaration into the one before, so mass, interfaces and the spec checks lost every name after it, and the guide said the statements around a grammar error still read","evidence":"blind review of 413b9a6, compare.ts and tree.mjs: export function before(){ const v = window; } export function after(){} read only before; the old hand reader read both","files":[],"class":"parse-gap","introduced":"c30238c","caught":"review","binding":"none: this session owns no active work order"} +{"id":"df-aad5bf07","kind":"defect","at":"2026-10-27T00:58:43.406Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"3a49cd3","dirty":true,"what":"the parse store's defenses against a repository claimed more than they held: the seal signed the fingerprint and not the contents, so a store's genuine first line over a forged body was read, and the test of forged stores wrote a malformed body the shape check refused first, so it never tested the seal; a committed folder named as the store's file made every warm-up throw, a committed lock stamped ahead held every warm-up off, and a committed unsigned audit.json put a false defect into every session start","evidence":"blind review of 413b9a6, forge.ts; refute of the signature break left the forged-store test green until its body was made well formed","files":[],"class":"over-claim","introduced":"cd16806","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-5d4a93ed","kind":"resolution","at":"2026-10-27T00:58:51.145Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"3a49cd3","dirty":true,"of":"df-42f25182","because":"treeSitter gains an optional alternate parser read with the same queries where the parser's tree errs and its own errs less; TypeScript names its TypeScript grammar beside TSX, and its queries name no JSX node so both compile; the guide now says a grammar error may swallow what follows; sweep: Go and Rust have one grammar each and no form one refuses that another reads, Python likewise","guard":"src/plugins/a parser reads TypeScript whole","binding":"none: this session owns no active work order"} +{"id":"rs-89eb982a","kind":"resolution","at":"2026-10-27T00:58:51.676Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"3a49cd3","dirty":true,"of":"df-aad5bf07","because":"the store's first line signs its contents and each log line signs itself, with this machine's key and the fingerprint; the forged-store test forges a well-formed body under a genuine first line; rewrite and lock survive a committed folder and refuse a future-stamped lock; the audit is signed and bounded; sweep: every file the store reads (base, log, audit, lock) checked for a repository's copy","guard":"src/plugins/the parse store never reaches past the project's own folders","binding":"none: this session owns no active work order"} +{"id":"en-43606f5d","kind":"enactment","at":"2026-10-27T00:59:05.679Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"3a49cd3","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --each over the seven touched bullets: 7 pass batched, 7 alone (runs/43578eac...fb7a6b92)"},"2":{"result":"done","evidence":"eight one-line breaks, each grep- or diff-confirmed: TS alternate dropped; alternate never compiled; sign() over the fingerprint alone; future lock honored; rewrite failure rethrown; notice signature unchecked (twice, two bullets); go marked hand-written in the guide"},"3":{"result":"done","evidence":"refute went red on each but the signature break, which left the forged-store test green: its forged body was malformed, so the shape check refused it first; the body was made well formed and the break then went red (made_up <- forged)"},"4":{"result":"done","evidence":"each restored from copies taken before the breaks (fix2/copies), cmp byte for byte"},"5":{"result":"done","evidence":"run --each after: 7 pass batched, 7 alone, every refutation witnessed"},"6":{"result":"deviated","because":"one red did not come at first (the signature break); the test was strengthened and refuted again rather than recording a decision, since no red had been recorded for it"}},"binding":"none: this session owns no active work order"} +{"id":"en-b299e31b","kind":"enactment","at":"2026-10-27T00:59:06.242Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"3a49cd3","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"resolved df-42f25182","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-42f25182, class parse-gap, caught review"},"2":{"result":"done","evidence":"Go, Rust and Python have one grammar each; no other plugin reads one file two ways"},"3":{"result":"done","evidence":"src/plugins/a parser reads TypeScript whole"},"4":{"result":"done","evidence":"dropped the alternate parser (refuted, witnessed)"},"5":{"result":"done","evidence":"rs-5d4a93ed; spec --check names no close with neither; it names a guard failure for the class, left for the owner (is the class a family)"}},"binding":"none: this session owns no active work order"} +{"id":"en-4f6a32f6","kind":"enactment","at":"2026-10-27T00:59:06.772Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"3a49cd3","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"resolved df-aad5bf07","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-aad5bf07, class over-claim, caught review"},"2":{"result":"done","evidence":"every file the store reads (its base, log, audit and lock) was checked against a repository's copy; the forged-store test was the one vacuous test found"},"3":{"result":"done","evidence":"src/plugins/the parse store never reaches past the project's own folders, beside src/plugins/a repository cannot stop a warm-up or speak through the store"},"4":{"result":"done","evidence":"signed the fingerprint alone; honored a future lock; rethrew a failed rewrite; said an unsigned audit (each refuted, witnessed)"},"5":{"result":"done","evidence":"rs-89eb982a; spec --check names no close with neither; it names a guard failure for the class, left for the owner (is the class a family)"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.55b91ea7.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.55b91ea7.jsonl new file mode 100644 index 00000000..e7b3ab31 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.55b91ea7.jsonl @@ -0,0 +1,4 @@ +{"id":"en-39cf9b5a","kind":"enactment","at":"2026-10-27T18:32:31.831Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"the full suite on the combined tree, 811 pass, before the break"},"2":{"result":"done","evidence":"the break the slot agent described: a kept read put back in keptModules through a cast, matched once"},"3":{"result":"done","evidence":"refute src/plugins/no core code reads a hand-written reader slot, red on its own assertion"},"4":{"result":"done","evidence":"kept-answers.ts restored from a copy, cmp identical"},"5":{"result":"done","evidence":"run --each over the bullet: pass batched and alone"},"6":{"result":"skipped","because":"the red came from the break"}},"binding":"none: this session owns no active work order"} +{"id":"d-a5c35add","kind":"decision","at":"2026-10-27T18:56:42.868Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"chose":"fix the blind review of 2558929 as one round: kept parses as one file each (loose objects) with the ownership check over the whole real path and every read; the grammar's reference corpus and expected trees from outside the patch; the prerelease shape test scoped to a lint, a real smoke check, ls-remote failing closed and a split job; the dead-end alarm counting unclassified defects, checking --component against files, resetting only on a human's acknowledgement and deduping worktree files by content; the slot refusal naming re-ejection, interfaces' hand-read imports refused, the scan test dropped","over":["patch each finding where the reviewers found it, keeping the segment store and the checks that trust what they check"],"because":"the review's deep faults shared one shape, a check trusting input the checked thing controls, and the store's remaining faults all came from segments and merges; the owner chose all six","human":"do them","binding":"none: this session owns no active work order"} +{"id":"d-320d365d","kind":"decision","at":"2026-10-27T19:09:20.336Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"chose":"demote src/plugins/the parse store touches its files only through StoreFolder: retired, StoreFolder is gone; what it guarded is held by src/plugins/the parse store is reached only inside its module and src/plugins/a kept parse is read only where it is the user's alone","over":[],"because":"the store is now one file per kept parse with ParseStore as its only holder; the text-matched gateway test was beaten by an export { } spelling in the review of 2558929, and an import of the module reads its exports as they are","binding":"none: this session owns no active work order"} +{"id":"d-e3e40b61","kind":"decision","at":"2026-10-27T19:09:20.600Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"chose":"demote src/plugins/a warm-up keeps the store small and runs once per project: retired, the store has no segments to merge and no lock; moved to src/plugins/a kept parse no process reads is swept and src/plugins/two warm-ups at once need no lock","over":[],"because":"a kept parse is a file of its own whose time says when it was last read, so its age is its own and no merge is needed; two writers cannot spoil a store of files each written whole, so a lock only saved work, and its taking over let eight of eight warm-ups run at once in the review of 2558929","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.57e39de0.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.57e39de0.jsonl new file mode 100644 index 00000000..2f95a0d2 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.57e39de0.jsonl @@ -0,0 +1 @@ +{"id":"en-9016f69c","kind":"enactment","at":"2026-10-27T18:32:20.860Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"7934a9d","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"the full suite on the combined tree, 811 pass, before the break"},"2":{"result":"done","evidence":"the break the slot agent described: a kept read put back in keptModules through a cast, matched once"},"3":{"result":"done","evidence":"refute src/plugins/no core code reads a hand-written reader slot, red on its own assertion"},"4":{"result":"done","evidence":"kept-answers.ts restored from a copy, cmp identical"},"5":{"result":"done","evidence":"run --each over the bullet: pass batched and alone"},"6":{"result":"skipped","because":"the red came from the break"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.61870e49.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.61870e49.jsonl new file mode 100644 index 00000000..2fa51819 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.61870e49.jsonl @@ -0,0 +1,5 @@ +{"id":"d-9f54b654","kind":"decision","at":"2026-10-26T21:35:35.168Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a63081e","dirty":true,"classifies":{"of":"df-53e501ca","class":"silent-skip"},"chose":"classify df-53e501ca: class silent-skip","over":[],"because":"misfiled as parse-gap on 2026-10-23: nothing was misread; one file gopls could not answer ended the reading of the whole Go language with no word of it, which is the silent-skip family (a reading that reads nothing and says nothing); left as parse-gap its guard stood for every parse gap and made df-7ac38ee4 read as a guard failure","cites":["df-53e501ca"],"binding":"none: this session owns no active work order"} +{"id":"d-1ad22dfb","kind":"decision","at":"2026-10-26T21:35:55.656Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a63081e","dirty":true,"chose":"lexicon apply lp-119f7f139375afc6e575ca65 {\"change\":{\"action\":\"define\",\"name\":\"defect\",\"entry\":{\"properties\":{\"family parse-gap\":\"A reader of source, shell or spec text misses a shape its language allows. A family: every hand-written reader (entrance rules, the shell reader, a plugin's import reader) misses shapes in its own way, so each defect closes with its own guard or a decision, and a later one is no guard failure; a reader moved onto a parser leaves it for that parser's guards.\"}},\"drop\":[\"properties.class parse-gap\"],\"because\":\"parse-gap held nine defects across entrance detection, Python URL patterns, the shell reader and Python's imports, which no one guard covers, so the first guard any of them got (df-53e501ca's, itself misfiled) made a later Python import defect (df-7ac38ee4) read as its failure; a family is the class too broad for one guard\",\"removed\":{\"properties.class parse-gap\":\"A reader of source, shell or spec text misses a shape its language allows.\"}},\"human\":\"proceed\"}","over":["keep parse-gap a class, so the first guard any reader gets stands for every reader's parse gaps"],"because":"parse-gap is the class too broad for one guard: its nine defects span entrance rules, Python URL patterns, the shell reader and Python's imports, and each reader misses shapes its own way","binding":"none: this session owns no active work order"} +{"id":"en-e099a803","kind":"enactment","at":"2026-10-26T21:36:13.722Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a63081e","dirty":true,"practice":"src/lifecycle/settle a domain term","version":"f51dc0a6","trigger":"command lexicon propose","steps":[{"text":"read the term's live uses before naming it: coherence lexicon review "},{"text":"decide what it is: the project's own concept, an alias of one, a property of one (a field, a column, a unit), or an ordinary programming word that needs no entry"},{"text":"settle a contested term from the project's own history (commit messages, pull request discussion) and record the tie-break with decide","leaves":"the decision's id"},{"text":"when the history does not settle it, escalate instead of deciding: two live senses that no record separates, the owner's word colliding with a name the lexicon rejected, or any rename, retire, reject or lift of a concept; carry on with the term provisional, and apply only with the human's words","leaves":"the escalation's id"},{"text":"before rejecting a name, count the findings it would create; a word in ordinary use gets a qualifying rename, not a bare rejection"},{"text":"propose, then apply with because and over; a human ruling carries the human's words with --human, and none is ever invented"},{"text":"run coherence lexicon --check","leaves":"0 rejected names and 0 unknown nouns beyond the baseline"}],"pitfalls":["rejecting a bare word turned 227 uses of a language keyword into findings (rt-cdcf2a29)","field and column names were nominated as unknown nouns until they were filed as properties of their concepts (d-3283157b)","identifiers written in backticks in specs were nominated as unknown nouns (d-9e7b9247)","common programming words kept as rejected names made hundreds of findings in ordinary code (d-f77ce193)","the owner's own word for a thing collided with a name the lexicon had rejected for another concept (c-c05b409e)","new nouns were left undeclared because the lexicon was outside the session's scope, where an escalation would have reached the owner (u-de8416b2)"],"results":{"1":{"result":"done"},"2":{"result":"done"},"3":{"result":"skipped","because":"not a contested term: a defect class's kind changed, settled by the owner's own word"},"4":{"result":"skipped","because":"the owner ruled directly (proceed), recorded with --human on d-1ad22dfb"},"5":{"result":"skipped","because":"no name rejected"},"6":{"result":"done"},"7":{"result":"done","evidence":"lexicon --check: 0 rejected names, 0 unknown nouns (593 files)"}},"binding":"none: this session owns no active work order"} +{"id":"en-66ebf828","kind":"enactment","at":"2026-10-26T21:36:14.107Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a63081e","dirty":true,"practice":"src/lifecycle/carry a lexicon change through","version":"f28a1b08","trigger":"command lexicon apply","steps":[{"text":"write the first sentence as the definition a session needs at a glance; the lexicon has no token ceiling; the start injection presents at most 2,000 tokens of it and decays the least recently named concepts to fit (d-2b4c96a2, d-f0da2f1f)"},{"text":"mark a concept \"protected\": true only when a human asks for it to stay whole however long the journal goes without naming it"},{"text":"before a reject or a rename, count the findings it would create across the corpus; a word in ordinary use or a language keyword gets a qualifying rename instead of a bare rejection"},{"text":"propose, then apply with because and over; a human ruling carries the human's words with --human, and none is ever invented"},{"text":"declare a new noun before any code, spec, or record uses it"},{"text":"update every concept whose definition or related list names the changed one"},{"text":"rename once, everywhere: files, commands, modules, Scope views, npm scripts, and refuse the old name with a one-line migration"},{"text":"run the vocabulary check","leaves":"lexicon check with 0 rejected names and 0 unknown nouns"}],"pitfalls":["rejecting a bare word turned 227 uses of the TypeScript keyword into findings (d-5060eaab, rt-cdcf2a29)","a fixed token ceiling was crossed and trimmed afterwards three times, and once its test was already red for the next session (d-3eb04416, d-7f5b5203, d-beedd69e, u-1c5215fe); the ceiling is gone (d-2b4c96a2)","a rejected alternative of three words or fewer becomes a name the check enforces; write it as a sentence when the word is in ordinary use (d-7c0ecc04)","a rejected name sat in a concept's related list after its concept was renamed (d-572be38e)","new nouns were left undeclared because the lexicon was outside the work order's write scope; escalate rather than leave them (u-de8416b2)"],"results":{"1":{"result":"skipped","because":"no definition's first sentence changed; one property of defect moved from class to family"},"2":{"result":"skipped","because":"no concept protected"},"3":{"result":"skipped","because":"no reject or rename"},"4":{"result":"done"},"5":{"result":"skipped","because":"no new noun"},"6":{"result":"done"},"7":{"result":"skipped","because":"no rename"},"8":{"result":"done","evidence":"lexicon --check: 0 rejected names, 0 unknown nouns (593 files)"}},"binding":"none: this session owns no active work order"} +{"id":"en-b3a66365","kind":"enactment","at":"2026-10-26T21:36:14.481Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a63081e","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"command classify","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"classification of df-53e501ca as silent-skip, recorded with its why"},"2":{"result":"skipped","because":"a reclassification of a closed defect; its sweep stands (rs-e9a8ede4)"},"3":{"result":"skipped","because":"df-53e501ca keeps its witnessed guard"},"4":{"result":"skipped","because":"its guard's refutation was witnessed at its close"},"5":{"result":"skipped","because":"already closed (rs-e9a8ede4); spec --check names no close with neither"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.7666dd0d.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.7666dd0d.jsonl new file mode 100644 index 00000000..3b75bcf0 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.7666dd0d.jsonl @@ -0,0 +1,9 @@ +{"id":"df-11317061","kind":"defect","at":"2026-10-26T21:49:39.098Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"what":"the bundled Python plugin fails its own plugin check on tree-sitter-pilot: its check project's render.py was rewritten with a from-import spanning lines (46d80e0) while its references and bypasses still named the old lines (render.py:1 and :6, now :2 and :9), and no test failed, since the per-language test runs the whole plugin check but asserts only the four reading duties","evidence":"coherence plugin check python on tree-sitter-pilot 870296d: references missed shop/api/render.py:1, :6, reported :2, :9; chokepoint bypasses :2, :9, not :1, :6; npm test passed (774/0)","files":[],"class":"structure-drift","introduced":"46d80e0","caught":"self","binding":"none: this session owns no active work order"} +{"id":"df-e2663a97","kind":"defect","at":"2026-10-26T21:53:24.220Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"what":"the Python adapter's references to a name sometimes leave out a star import that brings it in: over Python's check project with from shop.store.secrets import * in render.py, one plugin check reported SECRET_COLUMNS's references without render.py:6 and the runs after it with it, and one batched test run failed the same way while the same test passed alone, so a chokepoint's bypass through a star import can read graded one run and missed the next","evidence":"plugin check python on tree-sitter-pilot, 2026-10-26: first run after the check project changed: references reported render.py:3 and :13, not :6; three later runs reported :6; the batched run of the per-language duty tests failed once and passed on rerun; moved the glob import to shop.store (no protected name) for the check project, five runs stable","files":[],"class":"silent-skip","introduced":"pre-existing","caught":"self","binding":"none: this session owns no active work order"} +{"id":"df-03839b92","kind":"defect","at":"2026-10-26T22:01:22.841Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"what":"three bullets' via named no test by its exact title, so a full batched run graded each 'no test ran' (fail) while the same bullet run alone passed by pattern: every bundled language plugin gives every reading (the per-language tests were titled ': '), the new own-plugin-check bullet the same way, and a tool hook over the latency budget says so (its test title gained ', and regulate names stops over it' in #130, the via never did); run --each printed fail batched and pass alone without saying they disagreed","evidence":"run --invariant 'every bundled language plugin gives every reading' on tree-sitter-pilot: no test ran under the name ...; alone: pass; a static sweep of every via against every test and describe title in src found these three","files":[],"class":"structure-drift","introduced":"pre-existing","caught":"self","binding":"none: this session owns no active work order"} +{"id":"d-05b016d7","kind":"decision","at":"2026-10-26T22:01:44.163Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"chose":"close df-03839b92 by fixing its three instances (two vias now name a describe group the tests sit in, one via restated to its test's title) and leave its class guard as an open requirement in src/enforcement, a via that maps to no test is said","over":["build the run --each check now, inside the plugin-architecture work"],"because":"the instances are fixed and witnessed green batched and alone; the guard is a change to run's batched mapping that adopters' runs share, so it gets its own bullet, refutation and review rather than riding a plugin pull request","binding":"none: this session owns no active work order"} +{"id":"rs-7ba68cc8","kind":"resolution","at":"2026-10-26T22:01:51.765Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"of":"df-03839b92","because":"the per-language plugin tests sit under describe groups titled by the two vias that named them by prefix, and the latency budget bullet's via is its test's title; a static sweep of every via against every test and describe title in src finds none other; batched and alone both pass for all three","decision":"d-05b016d7","binding":"none: this session owns no active work order"} +{"id":"rs-8ef2819f","kind":"resolution","at":"2026-10-26T22:01:52.150Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"of":"df-11317061","because":"Python's check project's references and bypasses name the lines its rewritten render.py holds, and the per-language test now holds every duty of a bundled plugin's own plugin check, not the reading duties alone; sweep: plugin check of each bundled language plugin passes (typescript, python, rust, go)","guard":"src/plugins/every bundled language plugin passes its own plugin check","binding":"none: this session owns no active work order"} +{"id":"en-e82ec4ed","kind":"enactment","at":"2026-10-26T22:05:16.409Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"every bundled language plugin passes its own plugin check\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl: pass batched and alone"},"2":{"result":"done","evidence":"a reference line in plugins/python/check.json set one off (render.py:12 for :13); diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl; confirmed by node --test on python's own plugin check: references missed shop/api/render.py:12"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/check.json)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl: pass batched, refutation witnessed, and alone"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} +{"id":"en-6a8e1d29","kind":"enactment","at":"2026-10-26T22:05:16.765Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"a shape a project writes and no check project holds is named\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl: pass batched and alone"},"2":{"result":"done","evidence":"the untested filter in shapesText made checked < 0; diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl; confirmed by node --test on the test's own AssertionError"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/shapes.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl: pass batched, refutation witnessed, and alone"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} +{"id":"en-d09fda74","kind":"enactment","at":"2026-10-26T22:05:17.123Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"command resolved df-*","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-11317061 and df-03839b92 recorded with --class structure-drift, --introduced, --caught self"},"2":{"result":"done","evidence":"df-11317061: plugin check of every bundled language plugin run, all pass; df-03839b92: every via in every spec checked against every test and describe title in src, three found, all fixed"},"3":{"result":"done","evidence":"df-11317061 guarded by src/plugins/every bundled language plugin passes its own plugin check; df-03839b92 decided (d-05b016d7), its class guard an open requirement in src/enforcement"},"4":{"result":"done","evidence":"the guard's refutation red then witnessed in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl"},"5":{"result":"done","evidence":"rs-8ef2819f, rs-7ba68cc8; spec --check 0 problems"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.9579b3de.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.9579b3de.jsonl new file mode 100644 index 00000000..588b84b1 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.9579b3de.jsonl @@ -0,0 +1,13 @@ +{"id":"df-04fddaf1","kind":"defect","at":"2026-10-27T04:00:07.981Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"what":"a parse store log a repository commits held every reading process for seconds: each of its lines cost a signature, with no bound on lines or size, so a log of a million four-byte lines, which git stores as almost nothing, put a hook past its 3 s budget","evidence":"blind review of 45d4538, probes/biglog.ts: 17 reads took 4,358 ms over a 16 MB log and 16,870 ms over 64 MB (1,005 ms before the per-line signature)","files":[],"class":"cost","introduced":"45d4538","caught":"review","binding":"none: this session owns no active work order"} +{"id":"df-8b32c22b","kind":"defect","at":"2026-10-27T04:00:08.243Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"what":"the parse store's defenses claimed more than they held: a folder or link at warming.lock turned the warm-up off for good, a process's own append hid another's discard so the warm server read parses its audit had found stale, a pipe at the log's path hung the process, an empty key file left every kept parse unreadable for good, and no test went red when the log's signature check was removed or the alternate parser was fingerprinted by name","evidence":"blind review of 45d4538: probes lockdir.ts (skipped:true), reload.ts masked (A still read stale), fifo.ts (hung), shortkey.ts (audited 0, parsed 30 each time); staged breaks B2 and B7 left every test green","files":[],"class":"over-claim","introduced":"45d4538","caught":"review","binding":"none: this session owns no active work order"} +{"id":"df-f1d6f9ce","kind":"defect","at":"2026-10-27T04:00:08.512Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"what":"the alternate parser was chosen by how many error nodes each tree held, so TSX's one error swallowing a whole file mid-edit beat the TypeScript grammar's two small ones and every declaration after an old-style cast was lost again, and it was compiled up front in every process, hooks among them","evidence":"blind review of 45d4538, probes/alt.ts: TSX 1 error over 158 bytes, TypeScript 2 over 12, declarationsOf empty; cost2.ts: the TypeScript reader built in 96 ms with the alternate, 53 ms without","files":[],"class":"parse-gap","introduced":"45d4538","caught":"review","binding":"none: this session owns no active work order"} +{"id":"df-7f3e3885","kind":"defect","at":"2026-10-27T04:00:08.773Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"what":"the patched TypeScript scanner read every character past ASCII as part of a name, so an expression continued onto a line by in or instanceof followed by a Unicode space (a no-break space, an ideographic space) became an error that parsed clean before; a member named instanceof still erred, a bare & before a JSX string's quote still took the quote, and the test passed with three of the claimed fixes removed","evidence":"blind review of e8f802e: const r = a\\n in\\u00a0b erred in both patched grammars, clean in stock and in tsc 5.9.3; a build with in ?, the instanceof check and the character-reference test reverted passed the test","files":[],"class":"parse-gap","introduced":"e8f802e","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-7dde5ab5","kind":"resolution","at":"2026-10-27T04:00:21.020Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"of":"df-04fddaf1","because":"a log line is checked only where its signature is 43 characters, the log is read a chunk at a time and no further once more than LOG_TORN_MAX lines fail, and a store or log over STORE_MAX_BYTES is never read: 17 reads over a planted 16, 64 and 255 MB log take 4 ms, as over none; sweep: the store's other files (its base, one signature over the whole body, and the audit, one small file) were checked for a per-line cost and hold none","guard":"src/plugins/a store's log costs a repository nothing and lies to no reading","binding":"none: this session owns no active work order"} +{"id":"rs-94d73a75","kind":"resolution","at":"2026-10-27T04:00:21.592Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"of":"df-8b32c22b","because":"a folder or link at the lock's path lets the warm-up go on unlocked; a flush that finds the store changed by another process drops what it loaded so the next get reads it again; the log is opened O_NONBLOCK and appended only where fstat says a regular file; the key is written under a temporary name and linked into place, and a key file too short is replaced; tests now forge a log line, discard under a long-lived reader after its own flush, plant a pipe and an empty key, and fingerprint the alternate as a file of its own; sweep: every claim of the three store bullets was held to a staged break, nine in all, each red","guard":"src/plugins/a long-lived process reads what other processes did","binding":"none: this session owns no active work order"} +{"id":"rs-8ba96de3","kind":"resolution","at":"2026-10-27T04:00:22.147Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"of":"df-f1d6f9ce","because":"the alternate is chosen where its errors cover fewer bytes of the text (an error node its span, a missing node one), and it is compiled the first time a tree errs, its queries refused by name then; sweep: errorsIn had no other caller, and no other plugin names an alternate","guard":"src/plugins/a parser reads TypeScript whole","binding":"none: this session owns no active work order"} +{"id":"rs-332535f9","kind":"resolution","at":"2026-10-27T04:00:22.695Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"of":"df-7f3e3885","because":"the scanner ends a name at JavaScript's Unicode white space and line terminators, a member named instanceof ends the line before it as one named in does (before : ? =), and a JSX string's fragment never takes its closing quote; the test adds in?:, instanceof and instanceof_x members, a class field in, an & before each quote, two operators after a Unicode space, and asserts & and { read as character references; sweep: 17,106 PostHog files, stock against patched: 191 erring files become 52, 85 declarations come back, none lost, none newly erring","guard":"src/plugins/the TypeScript parsers read what their release cannot","binding":"none: this session owns no active work order"} +{"id":"en-6cfea708","kind":"enactment","at":"2026-10-27T04:00:37.482Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"resolved df-04fddaf1","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-04fddaf1, class cost, caught review"},"2":{"result":"done","evidence":"the store's base (one signature over its body) and audit (one small file) hold no per-line cost"},"3":{"result":"done","evidence":"src/plugins/a store's log costs a repository nothing and lies to no reading"},"4":{"result":"done","evidence":"every log line read; no bound on failed lines"},"5":{"result":"done","evidence":"rs-7dde5ab5; family, so no guard failure"}},"binding":"none: this session owns no active work order"} +{"id":"en-579c5b15","kind":"enactment","at":"2026-10-27T04:00:38.017Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"resolved df-8b32c22b","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-8b32c22b, class over-claim, caught review"},"2":{"result":"done","evidence":"every claim of the three store bullets held to a staged break, nine in all"},"3":{"result":"done","evidence":"src/plugins/a long-lived process reads what other processes did, beside src/plugins/a repository cannot stop a warm-up or speak through the store"},"4":{"result":"done","evidence":"own append restamps; no O_NONBLOCK; short key kept; lock folder holds off; alternate by name (each refuted, witnessed)"},"5":{"result":"done","evidence":"rs-94d73a75; a guard failure for the class, left for the owner (is over-claim a family)"}},"binding":"none: this session owns no active work order"} +{"id":"en-0bb6ad58","kind":"enactment","at":"2026-10-27T04:00:38.547Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"resolved df-f1d6f9ce","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-f1d6f9ce, class parse-gap, caught review"},"2":{"result":"done","evidence":"errorsIn had no other caller; no other plugin names an alternate"},"3":{"result":"done","evidence":"src/plugins/a parser reads TypeScript whole, beside src/plugins/a parser is held to what Coherence reads"},"4":{"result":"done","evidence":"chosen by count; compiled up front (each refuted, witnessed)"},"5":{"result":"done","evidence":"rs-8ba96de3; family, so no guard failure"}},"binding":"none: this session owns no active work order"} +{"id":"en-6a2663bc","kind":"enactment","at":"2026-10-27T04:00:39.117Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"resolved df-7f3e3885","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-7f3e3885, class parse-gap, caught review"},"2":{"result":"done","evidence":"17,106 PostHog files stock against patched, none lost, none newly erring"},"3":{"result":"done","evidence":"src/plugins/the TypeScript parsers read what their release cannot"},"4":{"result":"done","evidence":"e8f802e's parsers; no character reference told apart (each refuted, witnessed)"},"5":{"result":"done","evidence":"rs-332535f9; family, so no guard failure"}},"binding":"none: this session owns no active work order"} +{"id":"en-fb45c98d","kind":"enactment","at":"2026-10-27T04:00:39.666Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"e8f802e","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"the eight touched bullets passed batched and alone before the breaks"},"2":{"result":"done","evidence":"eleven one-change breaks: nine in syntax-trees.ts by exact replacement (refute-store.py), two parser builds (e8f802e's patch; no character reference told apart)"},"3":{"result":"done","evidence":"refute went red on each; the failing assertion read for each named the clause its break removed (the O_NONBLOCK break by the test's 20 s limit)"},"4":{"result":"done","evidence":"syntax-trees.ts restored from a copy and filecmp-checked after each; the parsers restored and cmp-checked"},"5":{"result":"done","evidence":"run --each over the eight: 8 pass batched, 8 alone, every refutation witnessed"},"6":{"result":"done","evidence":"every red came from its break"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.9a40ac94.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.9a40ac94.jsonl new file mode 100644 index 00000000..2bfeb676 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.9a40ac94.jsonl @@ -0,0 +1,4 @@ +{"id":"en-ba52f04e","kind":"enactment","at":"2026-10-26T23:25:37.973Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c3097c2","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"a registry's leaves share one parse store\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.502b1323.jsonl: pass batched (24.0 s) and alone (23.9 s)"},"2":{"result":"done","evidence":"two breaks, one line each: storeRootOf answering the project's own root; rewrite keeping only what the pass read; diffs read before each refute"},"3":{"result":"done","evidence":"two refutations red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.502b1323.jsonl; each confirmed by node --test on the test's own AssertionError"},"4":{"result":"done","evidence":"cmp against the copies taken before the breaks printed nothing (scratchpad pilot/copies/languages-fix.ts, syntax-trees-fix2.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.502b1323.jsonl: pass batched (24.2 s), refutation witnessed, and alone (24.0 s)"},"6":{"result":"skipped","because":"both reds came from their breaks, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} +{"id":"df-266d6a61","kind":"defect","at":"2026-10-26T23:25:38.243Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c3097c2","dirty":true,"what":"on a registry the parse store was kept per project root, so each leaf's warm-up kept its own store while mass and status run at the repository's top read a store no warm-up filled: every file parsed again each time, and their appends grew a log nothing folded in","evidence":"PostHog registry copy, battery on 1.11.0-beta.0: mass 16.4 s against main's 3.9 s, status 73.3 s against 45.0 s, .coherence/parses/python holding only a 30 MB .added.jsonl at the top and stores in posthog/, ee/api/ and the kernel leaf","files":[],"class":"cost","introduced":"46d80e0","caught":"probe","binding":"none: this session owns no active work order"} +{"id":"rs-6c9ac770","kind":"resolution","at":"2026-10-26T23:25:38.683Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c3097c2","dirty":true,"of":"df-266d6a61","because":"one store per repository at the registry's top (storeRootOf), a warm-up of a leaf pre-reads the top's files too, and the rewrite prunes by age (kept parses carry the day they were seen; anything seen in the last 14 days stays) so one leaf's pass keeps the others'; PostHog: warm-up 29 s cold, 2.4 s after, mass at the top 3.6 s; sweep: the store's other readers (hooks, plugin check's scratch projects, the census) take the same storeRootOf or no root","guard":"src/plugins/a registry's leaves share one parse store","binding":"none: this session owns no active work order"} +{"id":"en-d5196a0e","kind":"enactment","at":"2026-10-26T23:25:45.958Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c3097c2","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"command cli.* defect","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-266d6a61 recorded with --class cost --introduced 46d80e0 --caught probe"},"2":{"result":"done","evidence":"the store's every reader read: readings through languages.ts (storeRootOf), the warm-up (storeRootOf), the census and plugin check (no root, so no store); none keeps a store per leaf"},"3":{"result":"done","evidence":"src/plugins/a registry's leaves share one parse store"},"4":{"result":"done","evidence":"two refutations red then witnessed in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.502b1323.jsonl"},"5":{"result":"done","evidence":"rs-6c9ac770; spec --check run before commit"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.9c30bfad.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.9c30bfad.jsonl new file mode 100644 index 00000000..baaa1fd1 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.9c30bfad.jsonl @@ -0,0 +1,2 @@ +{"id":"rt-36b1facf","kind":"retraction","at":"2026-10-26T19:06:53.577Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"of":"d-60863cd3","because":"the guard it budgeted was vacuous: with tree.delete() dropped, 400 parses inside the reader still answered, since web-tree-sitter 0.27 frees a dropped tree when the collector finalizes it and the reader's query work keeps the collector running; the guard now counts every tree a parse makes until its delete(), which needs no budget","binding":"none: this session owns no active work order"} +{"id":"en-b2c29479","kind":"enactment","at":"2026-10-26T19:11:05.726Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"1aef204","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant (the four parser bullets) --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.714383b1.jsonl: 4 pass batched (28.9 s), 4 pass alone; the rewritten freed-tree guard alone again before its break: pass batched and alone"},"2":{"result":"done","evidence":"one line each, diff read before each refute: registry.ts twice filter && false; languages.ts importsOf read line by line; syntax-trees.ts unknown-capture filter && false, then the ready check && false; syntax-trees.ts tree.delete() dropped"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.714383b1.jsonl for each of the four bullets (2026-10-26T19:03:56Z, 19:04:31Z, two for the held-to bullet, and the freed-tree one); each red confirmed on its own assertion by node --test --test-name-pattern: AssertionError 'syntax.source beside a parser loads', AssertionError on the import list, 'Missing expected exception', assert.match on the runtime message, 'after 3 parses, 3 trees were never freed'. The first freed-tree guard stayed green with delete() dropped: nothing recorded, guard replaced, its budget decision retracted (rt-36b1facf)"},"4":{"result":"done","evidence":"cmp against the copy taken before each break printed nothing for registry.ts, languages.ts and syntax-trees.ts (scratchpad pilot/copies)"},"5":{"result":"done","evidence":"run --invariant (the four) --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.714383b1.jsonl: 4 pass batched (22.3 s), refutation witnessed on each; 4 pass alone (88.0 s)"},"6":{"result":"skipped","because":"every red came from its break, each seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a6da717c.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a6da717c.jsonl new file mode 100644 index 00000000..f20c6dfc --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a6da717c.jsonl @@ -0,0 +1,5 @@ +{"id":"df-b9b2d3ef","kind":"defect","at":"2026-10-27T00:11:49.044Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a3bdbc1","dirty":true,"what":"Rust's treeSitter separator shapes the specifier a kept parse holds, and the parse store's fingerprint digested only the parser and the queries, so a changed separator, or an edit to syntax-trees.ts's reading of a tree, read parses kept under the old one","evidence":"fingerprint in compile() (src/plugins/syntax-trees.ts at a3bdbc1) hashed binary, queries, STORE_FORMAT and the runtime version; speller(declared.separator) joins prefixes into the kept import.from text","files":[],"class":"duplicated-fact","introduced":"b5e683e","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-c54e7434","kind":"resolution","at":"2026-10-27T00:11:57.689Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a3bdbc1","dirty":true,"of":"df-b9b2d3ef","because":"the fingerprint digests every treeSitter input KEPT_FROM places as shaping a kept parse (a Record over the manifest's keys, so a new key fails to compile until placed), the runtime release, and syntax-trees.ts's own source; a test holds each left-out key to change no kept parse of any bundled plugin's check project, and a warm-up audits a sample of kept parses against fresh ones","guard":"src/plugins/a kept parse is filed under everything it depends on","binding":"none: this session owns no active work order"} +{"id":"d-a8c6dc95","kind":"decision","at":"2026-10-27T00:11:57.944Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a3bdbc1","dirty":true,"chose":"a warm-up re-parses a reservoir sample of 8 kept texts and, on any difference, discards the whole store and leaves an audit orient says for 7 days","over":["re-parse every kept text (doubles warm-up cost), heal silently with no notice (hides a fingerprint gap, the silent-skip shape), or drop only the differing entries (the rest share the same missed input)"],"because":"a stale entry means the fingerprint misses an input every entry shares, so no entry can be trusted; 8 parses cost milliseconds; the owner asked how we know the fact store is not stale and approved these guards","binding":"none: this session owns no active work order"} +{"id":"en-aee3b177","kind":"enactment","at":"2026-10-27T00:16:51.756Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a3bdbc1","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --each before the breaks: Go is read through its parser, a kept parse is filed under everything it depends on, a warm-up audits what is kept; 3 pass batched and 3 alone (runs/43578eac...ae0f5949)"},"2":{"result":"done","evidence":"three one-line breaks, each grep-confirmed alone: KEPT_FROM separator false; a runtime import of PLUGIN_API from plugin.ts; the audit filter prefixed with false &&"},"3":{"result":"done","evidence":"refute went red on each, on the test's own assertions (separator changes no kept parse of rust's check project; syntax-trees.ts imports at run time only the machine key's folder; the audit finds the sample stale)"},"4":{"result":"done","evidence":"restored from a copy taken before the breaks (st.orig2), cmp byte for byte"},"5":{"result":"done","evidence":"run --each after: 2 pass batched, 2 alone, refutation witnessed for both"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} +{"id":"en-db513f8b","kind":"enactment","at":"2026-10-27T00:16:52.275Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"a3bdbc1","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"resolved df-b9b2d3ef","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-b9b2d3ef, class duplicated-fact, introduced b5e683e, caught review"},"2":{"result":"done","evidence":"swept every input the kept Found depends on: compile() reads parser, queries, privateName (applied after the store, in the reader), separator (shapes the kept text: the sibling, fixed); resolve is read by languages.ts, not the parse; the extraction code itself was a second sibling, now digested; no other module writes a kept parse"},"3":{"result":"done","evidence":"src/plugins/a kept parse is filed under everything it depends on, beside src/plugins/a warm-up audits what is kept"},"4":{"result":"done","evidence":"refuted twice (separator left out; extraction code outside the digested module), witnessed in runs/43578eac...ae0f5949"},"5":{"result":"done","evidence":"rs-c54e7434; spec --check 0 problems, 0 closes with neither"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.aba4030f.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.aba4030f.jsonl new file mode 100644 index 00000000..05299a6c --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.aba4030f.jsonl @@ -0,0 +1,3 @@ +{"id":"d-2b2898cf","kind":"decision","at":"2026-10-27T04:37:35.307Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"ca263d3","dirty":true,"chose":"lexicon apply lp-a331f33392889fe4188b62df {\"change\":{\"action\":\"define\",\"name\":\"defect\",\"entry\":{\"properties\":{\"family duplicated-fact\":\"One fact kept in two places written apart, so one copy drifts from the other and a reader takes the stale one. A family: every fact can be kept twice in its own way (the project's name in the config and a lexicon, a parse's inputs in a manifest and a fingerprint), so each defect closes with its own guard or a decision, and a later one is no guard failure.\",\"family over-claim\":\"A reading credits more than its evidence shows: a control, a coverage, a verification or a defense counted where nothing checks it, so a gap reads closed. A family: every reading, test and claimed defense can over-claim in its own way (a scope's test-backed control, a parse store's signature and its untested clauses), so each defect closes with its own guard or a decision, and a later one is no guard failure.\"}},\"drop\":[\"properties.class duplicated-fact\",\"properties.class over-claim\"],\"because\":\"duplicated-fact and over-claim each held defects in unrelated places that no one guard covers: the project's-name guard read the parse fingerprint's missing separator as its failure, and the scope control guard read two parse-store defense defects as its failures; a family is the class too broad for one guard\",\"removed\":{\"properties.class duplicated-fact\":\"One fact kept in two places written apart, so one copy drifts from the other and a reader takes the stale one.\",\"properties.class over-claim\":\"A reading credits more than its evidence shows: a control, a coverage or a verification counted where nothing checks it, so a gap reads closed.\"}},\"human\":\"make the families, open the PR\"}","over":["keep duplicated-fact and over-claim classes, so the project's-name guard and the scope control guard stand for every later defect of their kind"],"because":"duplicated-fact and over-claim are classes too broad for one guard: their defects span the project's name, the parse fingerprint, the scope reading's controls and the parse store's defenses, and each closes with its own guard","binding":"none: this session owns no active work order"} +{"id":"en-8e565b2d","kind":"enactment","at":"2026-10-27T04:37:46.369Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"ca263d3","dirty":true,"practice":"src/lifecycle/settle a domain term","version":"f51dc0a6","trigger":"command lexicon propose","steps":[{"text":"read the term's live uses before naming it: coherence lexicon review "},{"text":"decide what it is: the project's own concept, an alias of one, a property of one (a field, a column, a unit), or an ordinary programming word that needs no entry"},{"text":"settle a contested term from the project's own history (commit messages, pull request discussion) and record the tie-break with decide","leaves":"the decision's id"},{"text":"when the history does not settle it, escalate instead of deciding: two live senses that no record separates, the owner's word colliding with a name the lexicon rejected, or any rename, retire, reject or lift of a concept; carry on with the term provisional, and apply only with the human's words","leaves":"the escalation's id"},{"text":"before rejecting a name, count the findings it would create; a word in ordinary use gets a qualifying rename, not a bare rejection"},{"text":"propose, then apply with because and over; a human ruling carries the human's words with --human, and none is ever invented"},{"text":"run coherence lexicon --check","leaves":"0 rejected names and 0 unknown nouns beyond the baseline"}],"pitfalls":["rejecting a bare word turned 227 uses of a language keyword into findings (rt-cdcf2a29)","field and column names were nominated as unknown nouns until they were filed as properties of their concepts (d-3283157b)","identifiers written in backticks in specs were nominated as unknown nouns (d-9e7b9247)","common programming words kept as rejected names made hundreds of findings in ordinary code (d-f77ce193)","the owner's own word for a thing collided with a name the lexicon had rejected for another concept (c-c05b409e)","new nouns were left undeclared because the lexicon was outside the session's scope, where an escalation would have reached the owner (u-de8416b2)"],"results":{"1":{"result":"done","evidence":"read the live uses: df-b9b2d3ef (duplicated-fact) and df-aad5bf07, df-8b32c22b (over-claim), each a guard failure against an unrelated guard"},"2":{"result":"done","evidence":"two properties of defect, each a class changed to a family"},"3":{"result":"skipped","because":"not a contested term: a defect class's kind changed, settled by the owner's word"},"4":{"result":"skipped","because":"the owner ruled directly (make the families), recorded with --human"},"5":{"result":"skipped","because":"no name rejected"},"6":{"result":"done","evidence":"proposed lp-a331f333, applied with because, over and --human (d-2b2898cf)"},"7":{"result":"done","evidence":"lexicon --check: 0 rejected names, 0 unknown nouns"}},"binding":"none: this session owns no active work order"} +{"id":"en-ee03be6c","kind":"enactment","at":"2026-10-27T04:37:54.635Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"ca263d3","dirty":true,"practice":"src/lifecycle/carry a lexicon change through","version":"f28a1b08","trigger":"command lexicon apply","steps":[{"text":"write the first sentence as the definition a session needs at a glance; the lexicon has no token ceiling; the start injection presents at most 2,000 tokens of it and decays the least recently named concepts to fit (d-2b4c96a2, d-f0da2f1f)"},{"text":"mark a concept \"protected\": true only when a human asks for it to stay whole however long the journal goes without naming it"},{"text":"before a reject or a rename, count the findings it would create across the corpus; a word in ordinary use or a language keyword gets a qualifying rename instead of a bare rejection"},{"text":"propose, then apply with because and over; a human ruling carries the human's words with --human, and none is ever invented"},{"text":"declare a new noun before any code, spec, or record uses it"},{"text":"update every concept whose definition or related list names the changed one"},{"text":"rename once, everywhere: files, commands, modules, Scope views, npm scripts, and refuse the old name with a one-line migration"},{"text":"run the vocabulary check","leaves":"lexicon check with 0 rejected names and 0 unknown nouns"}],"pitfalls":["rejecting a bare word turned 227 uses of the TypeScript keyword into findings (d-5060eaab, rt-cdcf2a29)","a fixed token ceiling was crossed and trimmed afterwards three times, and once its test was already red for the next session (d-3eb04416, d-7f5b5203, d-beedd69e, u-1c5215fe); the ceiling is gone (d-2b4c96a2)","a rejected alternative of three words or fewer becomes a name the check enforces; write it as a sentence when the word is in ordinary use (d-7c0ecc04)","a rejected name sat in a concept's related list after its concept was renamed (d-572be38e)","new nouns were left undeclared because the lexicon was outside the work order's write scope; escalate rather than leave them (u-de8416b2)"],"results":{"1":{"result":"skipped","because":"no definition's first sentence changed; two properties of defect moved from class to family"},"2":{"result":"skipped","because":"nothing protected"},"3":{"result":"skipped","because":"no reject or rename"},"4":{"result":"done","evidence":"lp-a331f333 applied with because, over and the owner's words (d-2b2898cf)"},"5":{"result":"skipped","because":"no new noun: family is defect's existing kind"},"6":{"result":"done","evidence":"no other concept's definition or related list names either class; the defect verb reads classes and families from the lexicon"},"7":{"result":"skipped","because":"no rename"},"8":{"result":"done","evidence":"lexicon --check: 0 rejected names, 0 unknown nouns; spec --check: 0 guard failures"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.b069dd90.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.b069dd90.jsonl new file mode 100644 index 00000000..6370c284 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.b069dd90.jsonl @@ -0,0 +1,2 @@ +{"id":"d-78b9fc37","kind":"decision","at":"2026-10-27T04:30:34.081Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"43198aa","dirty":true,"chose":"make the reviewed classes structural and hold each with Coherence: one StoreFolder gateway for every parse store file, its path function a chokepoint the compiler refuses outside it, and a totality oracle over every node:fs use in syntax-trees.ts; a store generation only rewrite makes, read back by every log line and reload; the TypeScript parsers pinned to build.sh's digests, which build only after the grammar's corpus and Coherence's pass, rebuilt byte for byte in CI; and src/lifecycle/prerelease.ts as the one way to cut a branch prerelease","over":["patching each call site with a test per instance | a corpus of TypeScript's own declaration files or of node_modules' scripts, which erred on the same one file under every build, broken or not | a chokepoint on newGeneration, which the TypeScript server cannot resolve inside a method"],"because":"the blind reviews found each defense missing at one more call site, a reload hidden by a write, a grammar regression no test saw, and a prerelease cut without main; a gateway, a generation only rewrite makes, a corpus naming each construct's tree, and one cutting script leave each class nowhere to recur","human":"do all four, using coherence to protect the behavior","binding":"none: this session owns no active work order"} +{"id":"en-b5963b28","kind":"enactment","at":"2026-10-27T04:30:34.652Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"43198aa","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"the new bullets' tests passed before the breaks"},"2":{"result":"done","evidence":"five one-change breaks: a direct rmSync past StoreFolder, a generation made at append, e8f802e's parsers swapped in, the ancestor check dropped, the manifest check dropped; the gateway chokepoint refuted by the run (the compiler refused an outside import)"},"3":{"result":"done","evidence":"refute went red on each, the failing assertion read for each naming its clause"},"4":{"result":"done","evidence":"each file restored from a copy and filecmp-checked; the parsers cmp-checked"},"5":{"result":"done","evidence":"run --each over ten bullets: 11 enforcements pass batched, 10 alone, every refutation witnessed"},"6":{"result":"done","evidence":"every red came from its break"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.bd61c944.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.bd61c944.jsonl new file mode 100644 index 00000000..3244a878 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.bd61c944.jsonl @@ -0,0 +1,18 @@ +{"id":"df-ef109f3e","kind":"defect","at":"2026-10-27T19:29:46.963Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"what":"a kept parse's age was its segment's time, which every merge restamped, so a parse no process read was carried forward for good; and a merge kept a parse by the segment it was first read from, so one written again today was dropped when an older segment held it first","evidence":"blind review of 2558929 (review7/store p1-retention, p2-from): after sixty days of merges the orphan parse was still kept; the parse a hook wrote today was gone after the merge","files":["src/plugins/syntax-trees.ts"],"component":"src/plugins","class":"duplicated-fact","introduced":"7934a9d","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-d2e953ee","kind":"resolution","at":"2026-10-27T19:29:47.444Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"of":"df-ef109f3e","because":"each kept parse is a file of its own whose time is stamped when read (at most once a day), and the sweep removes by that file's own time, so a parse's age is its own and no merge copies it; swept the store for every other time kept apart from what it describes: the audit's at is written with the audit, the swept file's time is the sweep's own; none other","guard":"src/plugins/a kept parse no process reads is swept","binding":"none: this session owns no active work order"} +{"id":"df-d3eacab6","kind":"defect","at":"2026-10-27T19:29:47.742Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"what":"the store was trusted by its cache folder's own owner and mode alone: a folder above it that others may write let another user move the cache away and put a store of theirs in its place, and a fingerprint's folder was never checked","evidence":"blind review of 2558929 (review7/store p7-trust): XDG_CACHE_HOME under a folder of mode 777, not sticky, read a forged parse; a fingerprint folder of mode 770 was read","files":["src/plugins/syntax-trees.ts"],"component":"src/plugins","class":"over-claim","introduced":"7934a9d","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-cd7432fe","kind":"resolution","at":"2026-10-27T19:29:48.234Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"of":"df-d3eacab6","because":"usersAlone checks every folder and link on the store's path, as written and as followed, owned by the user or the system and none others may write unless sticky, and the store's folders the user's own; each read checks the kept parse's folder and the file itself (no link, the user's, no one else may write, at most 32 MB); swept every file the store reads: kept parses, audits and the swept file, all through ownFile or lstat of the store's own folders","guard":"src/plugins/a kept parse is read only where it is the user's alone","binding":"none: this session owns no active work order"} +{"id":"df-a05047c4","kind":"defect","at":"2026-10-27T19:29:48.528Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"what":"one warm-up per project held only until its lock was taken over: several warm-ups took a dead lock over at once, and two merges at once could each remove a segment the other had not read","evidence":"blind review of 2558929 (review7/store p9-lock, p3-race): eight of eight warm-ups ran over a dead lock in one round; parses written during racing merges were missing afterwards","files":["src/plugins/syntax-trees.ts"],"component":"src/plugins","class":"over-claim","introduced":"7934a9d","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-65738843","kind":"resolution","at":"2026-10-27T19:29:49.018Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"of":"df-a05047c4","because":"no lock and no merge remain: each parse is written whole under a temporary name and renamed into place, so two writers cannot spoil each other, and each warm-up reads files in an order of its own so two at once mostly parse different files; swept for every other file written in place or shared between processes: audits and the swept file are written by the same whole-write, and none is changed in place","guard":"src/plugins/two warm-ups at once need no lock","binding":"none: this session owns no active work order"} +{"id":"df-f1f4499c","kind":"defect","at":"2026-10-27T19:29:49.314Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"what":"a long-lived reader held every segment it read in memory, about 40 MB of kept parses at PostHog's scale, and read the whole store again after any other warm-up's merge; and a merge killed midway left its temporary file for good","evidence":"blind review of 2558929 (review7/store p4-cost, p5-reload, p6-crash): hook-serve's memory held the store; the reading after another project's merge paid a full reload; a killed merge's temporary file stayed after every later warm-up","files":["src/plugins/syntax-trees.ts"],"component":"src/plugins","class":"cost","introduced":"7934a9d","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-b8a4ad38","kind":"resolution","at":"2026-10-27T19:29:49.801Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"of":"df-f1f4499c","because":"a reading opens the one file of each text it reads and holds only its last four texts' matches, so no store sits in memory and nothing is reloaded; the sweep removes a write's temporary file an hour on; measured on PostHog's 19,902 Python files: 32 s first warm-up, 2.0 s the next, mass 3.4 s; swept for every other reading that held a whole store: none remain","guard":"src/plugins/a long-lived process reads what other processes did","binding":"none: this session owns no active work order"} +{"id":"df-fd915434","kind":"defect","at":"2026-10-27T19:29:50.097Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"what":"the store's tests stayed green with the reload rule broken, its interval changed, parsesFolder exported through export { }, and the fingerprint folder's ownership check removed","evidence":"blind review of 2558929 (review7/store): four staged breaks, the store's tests green under each","files":["src/plugins/syntax-trees.ts"],"component":"src/plugins","class":"over-claim","introduced":"7934a9d","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-1357e526","kind":"resolution","at":"2026-10-27T19:29:50.583Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"of":"df-fd915434","because":"the reload and its interval are gone with the segments; the module's exports are read by importing it, so any export names itself; the fingerprint folder's check is refuted by the new user's-alone test; every bullet of the store was refuted again with a staged break of its own, each red on its own assertion","guard":"src/plugins/the parse store is reached only inside its module","binding":"none: this session owns no active work order"} +{"id":"en-b516d9c2","kind":"enactment","at":"2026-10-27T19:30:04.791Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"practice":"src/journal/close a defect","version":"b6c9d6b4","trigger":"command cli.* defect","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"name what let the bug be written (the state a value can hold that it never should, or a second way to do what one function should do alone), then sweep the codebase for every sibling of that shape and record the sweep: what was searched and each sibling found, or that it found none","leaves":"the representable shape, and the sweep"},{"text":"fix it so the code cannot express it again, in preference to a check at the site; when the dead-end reading names the defect's component (DEAD END in spec --check, Dead ends in orient), weigh a different design for that component first, not a narrower door in the same one, and record the choice, redesign or keep, as a decision: one door every caller must pass (a function or class its module keeps private, so the compiler, or a totality oracle where the language has no such check, refuses any other caller), a type that cannot hold the bad value, a walk with a stack of its own rather than recursion over what input controls, a fact derived where it is needed rather than kept twice; route every sibling the sweep found through it","leaves":"the door, type or derivation, and the siblings now routed through it; at a dead end, the decision choosing the design"},{"text":"guard or decide: name an invariant that fails on any second way to write the bug, a chokepoint the compiler grades or a totality oracle that reads the code and refuses each other door (another call, a name held under an alias, a module asked for by string), adding the bullet when none exists; or record a decision saying why fixing the instance suffices, or that only time or a scheduler can show the bug (a cost, a race), bounding it structurally all the same (a size every read passes, a lock only one process can take)","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a second way to write the bug rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)","the parse store's defences were checks written at each of its file system calls, and three blind reviews in a row found one more call without its check; one gateway, unexported and held by a parse of its module, was the fix that held (ca263d3, df-8b32c22b)","the gateway's totality oracle read only node:fs imported by name, so a require made with createRequire and the file system asked of process.getBuiltinModule each wrote past it with the test green (df-69c8ab4d)","a recursion over a parse tree was kept when its function was rewritten, so a file nested deep enough crashed every reading (df-6e6c2b80)","src/plugins, home of the parse store, collected 26 defects in 7 classes over 11 commits of blind review, each round closed by a check at the site its reviewer found and a test that the check existed, and the next round found faults in those checks (df-7c50adfe, df-aad5bf07, df-8b32c22b, df-2456bd98, df-69c8ab4d, df-ff68d46c, df-586f6367); the representation was the defect, a security-relevant cache inside the untrusted repository kept as mutable shared state, and nothing said so until the dead-end reading"],"results":{"1":{"result":"done","evidence":"df-ef109f3e (duplicated-fact), df-d3eacab6, df-a05047c4, df-fd915434 (over-claim), df-f1f4499c (cost), each with --component src/plugins, introduced 7934a9d, caught review"},"2":{"result":"done","evidence":"the representable shape was mutable shared state: segments merged and rewritten by several processes, a lock taken over, the store held in memory and reloaded, a parse's age kept as its segment's; swept the store for every file written in place or shared, every time kept apart from what it describes, and every folder read without its owner checked (named in each resolution)"},"3":{"result":"done","evidence":"redesign at the dead end, decided in d-a5c35add: one file per kept parse written once (loose objects), ParseStore the only holder, usersAlone over the whole path and ownFolder/ownFile at each read; no segment, merge, lock or reload remains to route through anything"},"4":{"result":"done","evidence":"src/plugins/a kept parse no process reads is swept; a kept parse is read only where it is the user's alone; two warm-ups at once need no lock; a long-lived process reads what other processes did; the parse store is reached only inside its module"},"5":{"result":"done","evidence":"13 refutations recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.89a170e0.jsonl, each break red on its own assertion, restored byte for byte, then run --each 12 alone, 12 pass"},"6":{"result":"done","evidence":"rs-d2e953ee, rs-cd7432fe, rs-65738843, rs-b8a4ad38, rs-1357e526; spec --check 0 problems"}},"binding":"none: this session owns no active work order"} +{"id":"en-bf6bfef9","kind":"enactment","at":"2026-10-27T19:30:05.265Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"practice":"src/journal/keep state where it is true","version":"55aa82c8","trigger":"command cli.* defect","steps":[{"text":"name the state the change touches: each truth (what is observed, entered or decided) and each value derived from one (a count, a cache, an index, a copy, a version repeated across files, a number written in a document)","leaves":"the truths and the derivations, each derivation naming the truth it comes from"},{"text":"store each truth once: where a second copy exists, compute it from the first (when built, read or shown) or remove it; a copy that must be kept (a cache, a snapshot) is filed by the truth it came from, by its digest or fingerprint, so it cannot disagree without being read as another","leaves":"each truth's one home, and each derivation's function or key"},{"text":"choose where state lives by who may write it and how long it lives: never where a party you do not trust can write (a tool's cache inside the project it reads), never a file two processes change in place; prefer records written once, whole, and never changed, over a file edited in turn","leaves":"each store's location, who may write it, and whether anything in it changes once written"},{"text":"make every output a function of the state: the same data gives the same answer whatever the time, the load, or what a process did before; where a reading must stop early (a time budget), it stops by what it counted and names what it did not read","leaves":"each output's inputs, and each place it can differ on the same data, removed or named"},{"text":"hold it with an invariant that recomputes each kept derivation from its truth and fails on a difference, or fails where a second writer of a truth appears; and record the choice of each store's home as a decision","leaves":"the invariant's / and its refutation, and the decision's id"}],"pitfalls":["Coherence kept its parse cache inside each project it read, so a repository could write the cache's files, and four rounds of blind review found about thirty defects in its defences; moved to the user's own cache, filed by the text's digest and written once, the defences were no longer needed (d-d1229127)","one version was kept in eight files, the package's and seven plugin manifests, and a prerelease checked them against each other because nothing derived them (df-089ac5a9, w-d112a3e4)","a journal kept per worktree showed one copy of a session's records, and the pane that read it showed nearly none (w-4c76c5ea)","numbers typed into documents and decisions from a measurement went stale or wrong, and had to be corrected by later decisions (d-2dfb13fc, d-e8f43329)","a reading stopped by a time budget gave different answers on the same checkout under different machine load (w-77d2fe8f)"],"results":{"1":{"result":"done","evidence":"truths: a text's parse under a fingerprint, when it was last read; derived: the warm-up's audit, the sweep's day, the reader's last four matches (from the parse files)"},"2":{"result":"done","evidence":"each parse once, a file named by the text's digest under the fingerprint; its last read is that file's own time; nothing copies a parse (no merge)"},"3":{"result":"done","evidence":"the user's cache, outside every project, writable by this user alone (usersAlone, ownFolder, ownFile); each file written once whole and renamed, never changed but its time stamp"},"4":{"result":"done","evidence":"a reading's answer is the parse file or a fresh parse of the same text, whichever process wrote it; the audit holds kept to fresh"},"5":{"result":"done","evidence":"src/plugins/a warm-up audits what is kept recomputes kept parses from their texts; src/plugins/two warm-ups at once need no lock fails on a second writer spoiling a parse; refuted in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.89a170e0.jsonl; decision d-a5c35add"}},"binding":"none: this session owns no active work order"} +{"id":"en-512422fd","kind":"enactment","at":"2026-10-27T19:30:34.545Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"deviated","because":"before the breaks the store's and user-dir's test files ran green whole (20 and 1 pass), not run --each; the --each run came after, in step 5"},"2":{"result":"done","evidence":"13 breaks in r8/refute-r8.py, each one exact replacement asserted to match once: per-read folder check, file mode check, O_NOFOLLOW, the path walk, the fingerprint folder check, link following, the reader's memory bound, an export, the read stamp, the daily sweep, the temporary file's age, a reinstated lock, a relative XDG_CACHE_HOME"},"3":{"result":"done","evidence":"each refute went red, 1 of 1 tests under its via; re-staged against the test file alone, each failed on its own assertion (named in each refuted: line), none by a hang, kill or timeout; recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.89a170e0.jsonl"},"4":{"result":"done","evidence":"each file restored from a copy taken before the break, filecmp byte for byte after every break"},"5":{"result":"done","evidence":"run --invariant over the 12 changed bullets --each: batched pass, 12 alone, 12 pass, every totality oracle that passed batched passes alone"},"6":{"result":"skipped","because":"every red came from its break; the refutations recorded in r8-slots were the slot agent's, enacted by it as en-58df6a7a"}},"binding":"none: this session owns no active work order"} +{"id":"df-e8424adc","kind":"defect","at":"2026-10-27T19:36:59.258Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"what":"the leak guard's own test failed once under the full suite: its fixture, which starts no process, was named for leaving a process shown as (node), a child the listing caught while it started or exited","evidence":"npm test on the merged round-8 tree, 2026-10-27: not ok 144, process 18969 (node) under folder.test.mjs, 5.1 s; the file alone passed three times and the unit suite again passed 816 of 816","files":["src/enforcement/leak-guard.ts"],"component":"src/enforcement","class":"load-flake","introduced":"unknown","caught":"test","binding":"none: this session owns no active work order"} +{"id":"d-32a88548","kind":"decision","at":"2026-10-27T19:37:13.691Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"chose":"amend src/journal/close a defect: step 3 lists the kinds of fix first and then, as its own sentence, weighing a different design when the dead-end reading names the component, so the list no longer reads as describing that decision","over":[],"because":"the review of 2558929 found the dead-end clause, set inside the list, made the doors read as the decision's; the alarm round's amendment d-35bc4af2 reworded it, and the store's close (en-b516d9c2) was enacted on the earlier wording in another checkout before the merge","cites":["en-b516d9c2","d-35bc4af2"],"binding":"none: this session owns no active work order"} +{"id":"en-df9e2309","kind":"enactment","at":"2026-10-27T19:37:14.145Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"practice":"src/journal/close a defect","version":"7ff6fcfb","trigger":"command cli.* defect","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"name what let the bug be written (the state a value can hold that it never should, or a second way to do what one function should do alone), then sweep the codebase for every sibling of that shape and record the sweep: what was searched and each sibling found, or that it found none","leaves":"the representable shape, and the sweep"},{"text":"fix it so the code cannot express it again, in preference to a check at the site: one door every caller must pass (a function or class its module keeps private, so the compiler, or a totality oracle where the language has no such check, refuses any other caller), a type that cannot hold the bad value, a walk with a stack of its own rather than recursion over what input controls, a fact derived where it is needed rather than kept twice; route every sibling the sweep found through it. When the dead-end reading names the defect's component (DEAD END in spec --check, Dead ends in orient), weigh a different design for that component before adding any such door to the one it has, and record the choice, redesign or keep, as a decision","leaves":"the door, type or derivation, and the siblings now routed through it; at a dead end, the decision choosing the design"},{"text":"guard or decide: name an invariant that fails on any second way to write the bug, a chokepoint the compiler grades or a totality oracle that reads the code and refuses each other door (another call, a name held under an alias, a module asked for by string), adding the bullet when none exists; or record a decision saying why fixing the instance suffices, or that only time or a scheduler can show the bug (a cost, a race), bounding it structurally all the same (a size every read passes, a lock only one process can take)","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a second way to write the bug rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)","the parse store's defences were checks written at each of its file system calls, and three blind reviews in a row found one more call without its check; one gateway, unexported and held by a parse of its module, was the fix that held (ca263d3, df-8b32c22b)","the gateway's totality oracle read only node:fs imported by name, so a require made with createRequire and the file system asked of process.getBuiltinModule each wrote past it with the test green (df-69c8ab4d)","a recursion over a parse tree was kept when its function was rewritten, so a file nested deep enough crashed every reading (df-6e6c2b80)","src/plugins, home of the parse store, collected 26 defects in 7 classes over 11 commits of blind review, each round closed by a check at the site its reviewer found and a test that the check existed, and the next round found faults in those checks (df-7c50adfe, df-aad5bf07, df-8b32c22b, df-2456bd98, df-69c8ab4d, df-ff68d46c, df-586f6367); the representation was the defect, a security-relevant cache inside the untrusted repository kept as mutable shared state, and nothing said so until the dead-end reading"],"results":{"1":{"result":"done","evidence":"df-e8424adc, class load-flake, introduced unknown, caught test"},"2":{"result":"skipped","because":"left open: seen once in two full runs, outside this round's six items; the likely shape is a process listing that counts a child caught mid-start or mid-exit, not yet confirmed"},"3":{"result":"skipped","because":"left open with the defect, unfixed this round"},"4":{"result":"skipped","because":"left open with the defect"},"5":{"result":"skipped","because":"left open with the defect"},"6":{"result":"skipped","because":"not closed; the defect stays open for the owner"}},"binding":"none: this session owns no active work order"} +{"id":"e-24d456c1","kind":"escalation","at":"2026-10-27T20:37:09.606Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"what":"src/plugins is at a dead end: redesign it or keep guarding?","because":"its defects share one representation: the parse store as mutable shared state, first inside the untrusted repository, then as segments several processes merged, locked and reloaded, each round closed by a check at the site the reviewer found and the next round faulting those checks","cites":["df-fd915434","d-d1229127","d-a5c35add"],"binding":"none: this session owns no active work order"} +{"id":"ak-6ae550c5","kind":"acknowledgement","at":"2026-10-27T20:37:14.646Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"2558929","dirty":true,"of":"e-24d456c1","because":"redesign: the parse store moved into the user's cache (d-d1229127) and then to one file per kept parse, written once, with no merge, lock or reload and the ownership check over the whole path and every read (d-a5c35add); the owner judged the dead end addressed by that redesign","human":"the dead end was addressed through redesign","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.c5c4ca40.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.c5c4ca40.jsonl new file mode 100644 index 00000000..af68a58f --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.c5c4ca40.jsonl @@ -0,0 +1,31 @@ +{"id":"d-08e78ac9","kind":"decision","at":"2026-10-27T13:05:14.084Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"chose":"the Scope page over Coherence's own tree is held under 5 MB in the bench job","over":["budget the runs and journal windows by the room the spec and lexicon leave under 3 MB"],"because":"the page stood at 3,207,357 bytes on beta-fixes-2 against the 3 MB cap, main at 3,005,377, and the owner chose the cap","human":"raise the cap to 5MB","binding":"none: this session owns no active work order"} +{"id":"df-6e6c2b80","kind":"defect","at":"2026-10-27T15:20:34.089Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"a source file nested ten thousand deep around an error crashed every warm-up and every mass: errorSpan measured a tree's errors by recursion, one stack frame per level, and the warm-up read its texts with no catch, so a 20 KB file of nested parentheses kept no store and made mass exit 70","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): deep.mjs, RangeError: Maximum call stack size exceeded at errorSpan; depth 2,000 passed, 10,000 threw","files":["src/plugins/syntax-trees.ts"],"class":"cost","introduced":"45d4538","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-7d6c548a","kind":"resolution","at":"2026-10-27T15:20:34.656Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-6e6c2b80","because":"errorSpan walks the tree with a stack of its own; the warm-up reads each text on its own, so one it cannot read is kept nowhere and the pass goes on; treeOf frees both trees on every path; sweep: the bundled readings' other walks over a tree (speller, holding, the census) loop over parents or matches without recursion, and a 20,000-deep error reads in Python, Rust and TypeScript","guard":"src/plugins/a repository cannot stop a warm-up or speak through the store","binding":"none: this session owns no active work order"} +{"id":"df-1ebcefa2","kind":"defect","at":"2026-10-27T15:20:34.900Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"a long-lived reader read a planted store again every second, whole, and a newline-free log quadratically: the reload compared the generation on disk with the one it had verified, which a seal it could not verify never set, and the log's reader copied every 1 MB chunk onto all it still held; a session start read each plugin folder's audit.json up to 256 MB","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): reload2.mjs, a 95 MB planted store cost 120 ms of every second; bigline.mjs, a newline-free log took 5,472 ms at 200 MB; audit.mjs, five 90 MB audits 1,980 ms","files":["src/plugins/syntax-trees.ts"],"class":"cost","introduced":"43198aa","caught":"review","binding":"none: this session owns no active work order"} +{"id":"d-05717677","kind":"decision","at":"2026-10-27T15:20:35.150Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"chose":"a long-lived reader's reload, the log's line reading and the audit's read are bounded by their code and by the store reviewer's probes, not by a unit test","over":["a unit test timing a reload or a read against a threshold"],"because":"each is observable only as time: no reading's answer differs, and a test that times a read fails under machine load whatever the change (the class load-flake); the probes re-run on the fix read a 95 MB planted store once in six seconds, a 200 MB newline-free log in 73 ms, and five 90 MB audits in 1 ms","binding":"none: this session owns no active work order"} +{"id":"rs-e550270b","kind":"resolution","at":"2026-10-27T15:20:35.391Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-1ebcefa2","because":"the reload looks at the store file's first line as it last read it, trusted or not, so a store this machine did not sign is read once and again only when it changes; a log's line is joined once when it ends; an audit is read only up to 4 KB and only 64 plugins' folders; flush loads the store before it appends, so it never tags its lines with a generation it did not verify","decision":"d-05717677","binding":"none: this session owns no active work order"} +{"id":"df-2456bd98","kind":"defect","at":"2026-10-27T15:20:35.625Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"a discard a long-lived reader never saw: a store that was its log alone had the generation none, and a discard that removed its files left it none, so a process that had loaded it read what the audit had found stale for as long as it lived, though the generation bullet claimed no write could hide another process's discard","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): aba.mjs, the reader answered stale_b after another process's warm-up discarded the store","files":["src/plugins/syntax-trees.ts"],"class":"over-claim","introduced":"43198aa","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-a339b2bf","kind":"resolution","at":"2026-10-27T15:20:36.193Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-2456bd98","because":"a discard seals the store empty under a generation of its own, through the one place a generation is made (seal), so every process that loaded it reads again; sweep: rewrite and discard were the only writers of the store's file","guard":"src/plugins/a long-lived process reads what other processes did","binding":"none: this session owns no active work order"} +{"id":"df-ed777a88","kind":"defect","at":"2026-10-27T15:20:36.425Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"the warm-up lock could be held by two warm-ups at once, and one no warm-up could read held every warm-up off for good: a dead lock was removed and created again in two steps, so two warm-ups that judged it dead could each remove the other's fresh lock, and a lock without read permission or past the size bound was read as nothing and never taken over","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): lockrace.mjs, six warm-ups over a dead lock, two ran in 2 of 5 trials; lockmode.mjs, a lock of mode 000 or a sparse 300 MB lock gave skipped:true on every run","files":["src/plugins/syntax-trees.ts"],"class":"over-claim","introduced":"43198aa","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-4bb1017e","kind":"resolution","at":"2026-10-27T15:20:36.987Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-ed777a88","because":"a lock is judged by its first line, and one no warm-up can read is judged dead; a dead lock is removed only under a taking-over lock that one warm-up alone creates, and only while it is still the one judged, so the lockrace probe runs one warm-up in 8 of 8 trials; a lock and every file the store creates is written whole under a temporary name and linked into place, so none is read empty; the race is held by the probe, not a unit test, since its interleaving is a scheduler's","guard":"src/plugins/a repository cannot stop a warm-up or speak through the store","binding":"none: this session owns no active work order"} +{"id":"df-69c8ab4d","kind":"defect","at":"2026-10-27T15:20:37.224Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"the gateway and generation tests were not total: a require made by createRequire, the file system asked of process.getBuiltinModule, the store's folder spelled inside a path, and a generation minted and the store's file written through an alias of ParseStore's folder each left both tests green","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): staged breaks A, B and C in ParseStore.flush; both structural tests green, the behavioural test red under A and B","files":["src/plugins/syntax-trees.test.ts"],"class":"over-claim","introduced":"ca263d3","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-c2b4fe63","kind":"resolution","at":"2026-10-27T15:20:37.774Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-69c8ab4d","because":"the gateway test refuses any string naming the file system's module outside its import, any require, dynamic import or built-in asked for by name, createRequire but to find web-tree-sitter, and the store's folder spelled in any string or template; the generation test holds that only seal makes a generation, only a rewrite or a discard seals, randomBytes is used only by newGeneration and the machine key, and ParseStore's folder is only called; each of the three breaks now turns its test red","guard":"src/plugins/the parse store touches its files only through StoreFolder","binding":"none: this session owns no active work order"} +{"id":"df-ff68d46c","kind":"defect","at":"2026-10-27T15:20:38.016Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"the parse store's defenses at .coherence and .coherence/parses, and its refusal to read through a link, were held by no test, and an append went through a hard link: removing each check left every test green, and a log that is a second name of a file outside the project was appended to","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): removing the parent link checks, O_NOFOLLOW on reads and STORE_MAX_BYTES each left syntax-trees.test.ts 20/20 green; append through a hard link reasoned from fstat, refuted here","files":["src/plugins/syntax-trees.ts","src/plugins/syntax-trees.test.ts"],"class":"over-claim","introduced":"ca263d3","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-fc19b5b6","kind":"resolution","at":"2026-10-27T15:20:38.544Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-ff68d46c","because":"the test commits .coherence and .coherence/parses as links, links a store this machine signed in from outside, and makes the log a hard link to a file outside the project; append refuses a file with more than one name; removing the folder check, O_NOFOLLOW on a read or the name count each turns the test red; STORE_MAX_BYTES stays in the code and out of the bullets, since only a read's time shows it","guard":"src/plugins/the parse store never reaches past the project's own folders","binding":"none: this session owns no active work order"} +{"id":"df-194f5620","kind":"defect","at":"2026-10-27T15:20:44.770Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"the warm-up a session start launches followed a project's symbolic links: a source file linking out of the project had its names kept in the project's store, and one linking to a pipe held the warm-up for good","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): warmlink.mjs, OUTSIDE_SECRET_TOKEN kept in .coherence/parses/typescript; a link to a FIFO held the warm-up past 8 s","files":["src/economy/warm-parses.ts"],"class":"path-identity","introduced":"46d80e0","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-f59c1263","kind":"resolution","at":"2026-10-27T15:20:45.307Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-194f5620","because":"the warm-up opens each source file without following a link and never waiting on a pipe, and reads only a regular file of at most 16 MB; sweep: the warm-up is the one reading a session start runs unasked; mass, structure and the plugin readings read what a person or agent asks of them, through the project's file walk","guard":"src/plugins/a repository cannot stop a warm-up or speak through the store","binding":"none: this session owns no active work order"} +{"id":"df-7cc06057","kind":"defect","at":"2026-10-27T15:20:45.541Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"the bare & fix in the TSX grammar renamed every & operator: alias(token.immediate('&'), string_fragment) shared one token with the & of an intersection type and a bitwise and, so each read as string_fragment, which no corpus of S-expressions shows","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): pat-tsx.wasm, type T = A & B and a & b each report their & as string_fragment; the symbol table diff shows it the only renamed token","files":["grammars/tree-sitter-typescript/coherence.patch","plugins/typescript/tree-sitter-tsx.wasm"],"class":"parse-gap","introduced":"e8f802e","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-1eef82d9","kind":"resolution","at":"2026-10-27T15:20:46.100Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-7cc06057","because":"the bare & in a JSX string is the pattern /&/, a token of its own; the test reads the & of an intersection type and a bitwise and as & nodes in both grammars; sweep: a symbol table diff of the four parsers named no other renamed token, and the PostHog sweep reads every file as before","guard":"src/plugins/the TypeScript parsers read what their release cannot","binding":"none: this session owns no active work order"} +{"id":"df-bf1275c5","kind":"defect","at":"2026-10-27T15:20:46.333Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"build.sh pinned a compiler that compiled nothing and downloaded the one that did unchecked: it required emcc 6.0.13, while tree-sitter-cli 0.27.1 compiles with a wasi-sdk clang and a binaryen wasm-opt it downloads with no checksum, and the CLI itself came from npm exec, whose install script downloads its binary unchecked; the docs and the CI comment said a breaking patch never merges, though main requires no check","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): a fake emcc that only prints 6.0.13 let build.sh rebuild both parsers byte for byte; CI log at b19875c: Downloading clang from wasi-sdk-34, wasm-opt version_132; gh api rules/branches/main: deletion, non_fast_forward, required_signatures","files":["grammars/tree-sitter-typescript/build.sh",".github/workflows/ci.yml","docs/plugins.md"],"class":"over-claim","introduced":"ca263d3","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-4b29f266","kind":"resolution","at":"2026-10-27T15:20:46.869Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-bf1275c5","because":"build.sh fetches the CLI's binary, wasi-sdk 34 and binaryen 132 for the host and checks each by its digest (matching GitHub's own asset digests), hands the compiler to the CLI by TREE_SITTER_WASI_SDK_PATH and TREE_SITTER_BINARYEN_PATH, unpacks tree-sitter-javascript from its checked tarball, keeps the CLI's caches in the build's folder and writes the bundled parsers only once each is its digest; the TypeScript parser rebuilt this way is byte for byte the one bundled; verify waits on typescript-parsers, and the claims say the checks fail, not that nothing merges","guard":"src/plugins/the TypeScript parsers are the ones their build makes","binding":"none: this session owns no active work order"} +{"id":"df-089ac5a9","kind":"defect","at":"2026-10-27T15:20:47.110Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"the prerelease script cut what it should refuse: an untracked file the tarball ships, HEAD only on a fork's branch or on a branch the remote had deleted, past a local tag named origin/main, a manifest a major version's bump left behind, and a release to whatever repository origin is","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): probes/probe.ts, prereleaseProblems() empty in cases A, B, C, D and F; npm pack --dry-run --json shipped the untracked file","files":["src/lifecycle/prerelease.ts"],"class":"over-claim","introduced":"ca263d3","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-ff9ee79b","kind":"resolution","at":"2026-10-27T15:20:47.639Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-089ac5a9","because":"the script releases to the repository package.json names, through the remote whose URL is it, fetches that remote with --prune, reads its main by its full ref name, asks that HEAD be on one of its branches, refuses any change or file git does not ignore, holds every manifest but a 0.x one to the package's version, and refuses arguments it does not take and a notes file that is not there","guard":"src/lifecycle/a prerelease carries main","binding":"none: this session owns no active work order"} +{"id":"df-467db56c","kind":"defect","at":"2026-10-27T15:20:47.885Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"what":"the patched grammar recovers less around a parenthesized import type, which errs with the stock grammar too, and the docs listed a comparison after an import type among the old errors: `x as import('x').T < y` newly errs, as it does after any other type and as tsc refuses it, and a file erring at (import('x').A) can lose a declaration after it","evidence":"blind review of ca263d3 (review4/store, review4/grammar, review4/claims probes): @aws-sdk/core httpAuthSchemes index.d.ts loses resolveAWSSDKSigV4Config; over about 80,000 real files 4 declarations fewer, 2,601 more; tsc 5.9.3 refuses x as import('a').T < y","files":["docs/plugins.md"],"class":"parse-gap","introduced":"e8f802e","caught":"review","binding":"none: this session owns no active work order"} +{"id":"d-6b0fbea9","kind":"decision","at":"2026-10-27T15:20:48.130Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"chose":"the patched TypeScript grammar keeps its import type rules as they are, and the plugin guide names what it newly errs on and where it recovers less","over":["make a parenthesized import type parse, with conflicts declared between the type-annotation import rules and the expression ones"],"because":"declaring the conflicts was unnecessary to the generator and raising the rules to the expressions' precedence opened new conflicts with primary_type; the form errs with the stock grammar too, the comparison is one tsc refuses, and over 80,000 files the patch reads 2,601 declarations more against 4 fewer","binding":"none: this session owns no active work order"} +{"id":"rs-4f949a45","kind":"resolution","at":"2026-10-27T15:20:48.365Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"of":"df-467db56c","because":"docs/plugins.md lists the comparison after an import type as newly erring, as with any other type and in tsc, and says the patched grammar can recover less around a parenthesized import type, with the counts","decision":"d-6b0fbea9","binding":"none: this session owns no active work order"} +{"id":"en-c8fe7a24","kind":"enactment","at":"2026-10-27T15:27:40.917Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"command cli.* defect","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-6e6c2b80 df-1ebcefa2 df-2456bd98 df-ed777a88 df-69c8ab4d df-ff68d46c df-194f5620 df-7cc06057 df-bf1275c5 df-089ac5a9 df-467db56c, each with --class, --introduced and --caught review"},"2":{"result":"done","evidence":"each resolution names its sweep (the tree walks, the store's writers, the warm-up as the one unasked reading, the four parsers' symbol tables, the PostHog sweep re-run identical)"},"3":{"result":"done","evidence":"guards src/plugins/a repository cannot stop a warm-up or speak through the store, a long-lived process reads what other processes did, the parse store touches its files only through StoreFolder, the parse store never reaches past the project's own folders, the TypeScript parsers read what their release cannot, the TypeScript parsers are the ones their build makes, src/lifecycle/a prerelease carries main; decisions d-05717677 (timing-only costs) and d-6b0fbea9 (parenthesized import type)"},"4":{"result":"done","evidence":"each guard's break staged and red on its own assertion (refuted: lines of 2026-10-27, refute5/6/7/8 in the scratchpad), restored byte for byte; run .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.073ad37a.jsonl green batched and alone"},"5":{"result":"done","evidence":"rs-7d6c548a rs-e550270b rs-a339b2bf rs-4bb1017e rs-c2b4fe63 rs-fc19b5b6 rs-f59c1263 rs-1eef82d9 rs-4b29f266 rs-ff9ee79b rs-4f949a45; spec --check: 0 problems, 0 closes with neither, 1 guard failure (df-194f5620 in path-identity, a real repeat)"}},"binding":"none: this session owns no active work order"} +{"id":"en-a810b4ff","kind":"enactment","at":"2026-10-27T15:27:41.515Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"edit **/*.spec.md adding refuted:","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"the touched bullets green before each break, in each break script's own full run of syntax-trees.test.ts and prerelease.test.ts"},"2":{"result":"done","evidence":"each break the smallest change to the behaviour a bullet claims (the recursion back in errorSpan, a discard that removes, the three gateway bypasses, the lock's old judgement, O_NOFOLLOW dropped from a read and from the warm-up's open, the name count dropped from append, the folder check emptied, the old TSX parser, an unchecked curl, and the five prerelease holes), each replacement asserted to match once"},"3":{"result":"deviated","because":"staged by script against the bullet's via test file (refute5.py, refute6.py, refute7, refute8) rather than refute , each red on its own assertion; the warm-up's link break first went red by the test's timeout on the pipe and was staged again so it fails on the assertion that the outside file is never read"},"4":{"result":"done","evidence":"each file restored from a copy taken before the break and compared byte for byte (filecmp)"},"5":{"result":"done","evidence":"run --each over the eleven touched bullets: 12 enforcements pass batched, 11 pass alone (rs-073ad37a's run file)"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} +{"id":"d-262d3cd3","kind":"decision","at":"2026-10-27T15:30:15.386Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"chose":"when fixing a bug or answering a code review, prefer the fix that leaves the bug structurally unrepresentable (one door the compiler or a totality oracle holds, a value that cannot be built wrong) over a check at the site, and keep it as an internal practice of Coherence's own","over":["fix each instance where it was found and guard it with a test of that instance"],"because":"the owner's direction after the fourth blind review, and their second message asked that it be recorded as a project practice for fixing bugs and responding to code review (not quoted: it uses a name the lexicon rejects); three reviews in a row found a parse-store defence missing at one more of 35 call sites, and the gateway that left those unrepresentable was the fix that held","human":"ensure these fixes make the bugs structurally unrepresentable","binding":"none: this session owns no active work order"} +{"id":"en-ff088d71","kind":"enactment","at":"2026-10-27T15:51:57.437Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"practice":"src/journal/leave a defect unrepresentable","version":"af898e4e","trigger":"explicit","steps":[{"text":"name what let the bug be written: the state a value can hold that it never should, or the second way to do what one function should do alone","leaves":"the representable shape, in the defect's evidence or the resolution's because"},{"text":"choose the structural fix before a check at the site: one door every caller must pass (a function or class the module keeps unexported, so the compiler refuses any other), a type that cannot hold the bad value, a walk with a stack of its own rather than recursion over what a project controls, a fact derived rather than kept twice; and route every sibling the sweep found through it","leaves":"the door, type or derivation, and the siblings now routed through it"},{"text":"hold the structure with an invariant that fails on any other way to write the bug: a chokepoint the compiler grades, or a totality oracle that parses the code and refuses each second door (another call, a name held under an alias, a module asked for by string), and stage one such door to see it go red","leaves":"the invariant's / and its refutation"},{"text":"where only time or a scheduler can show the bug (a cost, a race), say so in a decision and bound it structurally all the same (a byte cap every read passes, a lock only one process can take)","leaves":"the decision's id, or none needed"}],"pitfalls":["the parse store's defences were checks written at each of 35 file system calls, and three blind reviews in a row found one more call without its check; one gateway, unexported and held by a parse of the module, was the fix that held (ca263d3, df-8b32c22b)","the gateway's totality oracle read only node:fs imported by name, so a require made with createRequire and the file system asked of process.getBuiltinModule each wrote past it with the test green (df-69c8ab4d)","a recursion over a tree's errors was kept when its function was rewritten, so a file nested deep enough crashed every reading (df-6e6c2b80)"],"results":{"1":{"result":"done","evidence":"each of df-6e6c2b80..df-467db56c names its representable shape: recursion over a project-controlled depth, file opens at each call site, generation and first line settable anywhere, a lock any code could remove, a token alias, an unpinned download, a remote spelled by hand, a walk that kept anything not a folder"},"2":{"result":"done","evidence":"one opener (#openFile) for every store file; one method per file system effect in StoreFolder; seal the one maker of a generation; get and seal the one setters of what a process loaded; takeOver and unlock the one removers of the lock; isFileOnDisk the one test of every enumeration; fetch the one download in build.sh; package.json's repository the one release target"},"3":{"result":"done","evidence":"each held by a test that reads the code (syntax-trees.test.ts: per-effect doors, no recursion, single setters, anonymous tokens of their own spelling, verify needing every job; project-files.test.ts; prerelease.test.ts; user-dir.test.ts); ten second doors staged and each went red (refute9.py), the two new bullets refuted through refute"},"4":{"result":"done","evidence":"d-05717677 (the reload, the log's line reading and the audit read show only as time; each read is bounded by #openFile's size), and the lock race held by the probe (8 of 8 one warm-up) under the takeover lock only one process creates"}},"binding":"none: this session owns no active work order"} +{"id":"d-b12df633","kind":"decision","at":"2026-10-27T15:57:04.711Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"chose":"the guidance to leave a defect unrepresentable lives in the kernel practice close a defect, as its new third step and a sharpened guard step, and the internal practice leave a defect unrepresentable is removed","over":["keep leave a defect unrepresentable as a practice of its own, kernel or internal, beside close a defect"],"because":"both fire on the same commands and decide how a defect closes, so two practices would deliver overlapping guidance on every defect and drift apart; folded in, every Coherence-using project gets it with the practice it already runs; the removed practice's one enactment and d-262d3cd3 stand as its history","human":"should close a defect be refined to contain this guidance instead? / do it, commit, and let's do one last blind review pass","binding":"none: this session owns no active work order"} +{"id":"d-354e6716","kind":"decision","at":"2026-10-27T15:58:23.191Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"b19875c","dirty":true,"chose":"amend src/journal/close a defect: the sweep step now first names what let the bug be written; a new step fixes it so the code cannot express it again, before a check at the site; the guard step asks for an invariant that fails on any second way to write the bug, and a decision for what only time or a scheduler shows, bounded structurally; the refutation stages a second way to write the bug","over":["keep the three steps as en-c8fe7a24 enacted them and teach the structural fix in a practice of its own"],"because":"the owner's direction (d-b12df633, d-262d3cd3): each step still asks what it asked, a sweep, a guard over the whole class or a decision, and a refutation of the class's shape, now said as the shape the fix removes; three blind reviews in a row found a check missing at one more site until one door made the class unwritable","cites":["en-c8fe7a24"],"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.dd0ccfe5.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.dd0ccfe5.jsonl new file mode 100644 index 00000000..7dc156d9 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.dd0ccfe5.jsonl @@ -0,0 +1,3 @@ +{"id":"d-f70628b6","kind":"decision","at":"2026-10-26T23:29:23.810Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"17d1002","dirty":true,"chose":"lexicon apply lp-e0849a8883e836c84f70b9df {\"change\":{\"action\":\"define\",\"name\":\"defect\",\"entry\":{\"properties\":{\"family cost\":\"Work out of proportion to the answer: a hook or reading that reads far more than it needs, past the latency budget. A family: every hook, reading and store pays its own way (the dead-trigger check's triggers, a parse store kept per leaf of a registry), so each defect closes with its own guard or a decision, and a later one is no guard failure.\"}},\"drop\":[\"properties.class cost\"],\"because\":\"cost held defects in unrelated places (the dead-trigger check paying for its triggers, a parse store kept per registry leaf), which no one guard covers, so the dead-trigger check's guard read four later defects as its failures; a family is the class too broad for one guard\",\"removed\":{\"properties.class cost\":\"Work out of proportion to the answer: a hook or reading that reads far more than it needs, past the latency budget.\"}},\"human\":\"yes, make cost a family\"}","over":["keep cost a class, so the dead-trigger check's guard stands for every later cost defect"],"because":"cost is the class too broad for one guard: its defects span the dead-trigger check, the hooks and the parse store, and each pays its own way","binding":"none: this session owns no active work order"} +{"id":"en-8bf51092","kind":"enactment","at":"2026-10-26T23:29:26.087Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"17d1002","dirty":true,"practice":"src/lifecycle/settle a domain term","version":"f51dc0a6","trigger":"command lexicon propose","steps":[{"text":"read the term's live uses before naming it: coherence lexicon review "},{"text":"decide what it is: the project's own concept, an alias of one, a property of one (a field, a column, a unit), or an ordinary programming word that needs no entry"},{"text":"settle a contested term from the project's own history (commit messages, pull request discussion) and record the tie-break with decide","leaves":"the decision's id"},{"text":"when the history does not settle it, escalate instead of deciding: two live senses that no record separates, the owner's word colliding with a name the lexicon rejected, or any rename, retire, reject or lift of a concept; carry on with the term provisional, and apply only with the human's words","leaves":"the escalation's id"},{"text":"before rejecting a name, count the findings it would create; a word in ordinary use gets a qualifying rename, not a bare rejection"},{"text":"propose, then apply with because and over; a human ruling carries the human's words with --human, and none is ever invented"},{"text":"run coherence lexicon --check","leaves":"0 rejected names and 0 unknown nouns beyond the baseline"}],"pitfalls":["rejecting a bare word turned 227 uses of a language keyword into findings (rt-cdcf2a29)","field and column names were nominated as unknown nouns until they were filed as properties of their concepts (d-3283157b)","identifiers written in backticks in specs were nominated as unknown nouns (d-9e7b9247)","common programming words kept as rejected names made hundreds of findings in ordinary code (d-f77ce193)","the owner's own word for a thing collided with a name the lexicon had rejected for another concept (c-c05b409e)","new nouns were left undeclared because the lexicon was outside the session's scope, where an escalation would have reached the owner (u-de8416b2)"],"results":{"1":{"result":"done"},"2":{"result":"done"},"3":{"result":"skipped","because":"not a contested term: a defect class's kind changed, settled by the owner's word"},"4":{"result":"skipped","because":"the owner ruled directly (yes, make cost a family), recorded with --human"},"5":{"result":"skipped","because":"no name rejected"},"6":{"result":"done"},"7":{"result":"done","evidence":"lexicon --check: 0 rejected names, 0 unknown nouns"}},"binding":"none: this session owns no active work order"} +{"id":"en-e50c8071","kind":"enactment","at":"2026-10-26T23:29:26.518Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"17d1002","dirty":true,"practice":"src/lifecycle/carry a lexicon change through","version":"f28a1b08","trigger":"command lexicon apply","steps":[{"text":"write the first sentence as the definition a session needs at a glance; the lexicon has no token ceiling; the start injection presents at most 2,000 tokens of it and decays the least recently named concepts to fit (d-2b4c96a2, d-f0da2f1f)"},{"text":"mark a concept \"protected\": true only when a human asks for it to stay whole however long the journal goes without naming it"},{"text":"before a reject or a rename, count the findings it would create across the corpus; a word in ordinary use or a language keyword gets a qualifying rename instead of a bare rejection"},{"text":"propose, then apply with because and over; a human ruling carries the human's words with --human, and none is ever invented"},{"text":"declare a new noun before any code, spec, or record uses it"},{"text":"update every concept whose definition or related list names the changed one"},{"text":"rename once, everywhere: files, commands, modules, Scope views, npm scripts, and refuse the old name with a one-line migration"},{"text":"run the vocabulary check","leaves":"lexicon check with 0 rejected names and 0 unknown nouns"}],"pitfalls":["rejecting a bare word turned 227 uses of the TypeScript keyword into findings (d-5060eaab, rt-cdcf2a29)","a fixed token ceiling was crossed and trimmed afterwards three times, and once its test was already red for the next session (d-3eb04416, d-7f5b5203, d-beedd69e, u-1c5215fe); the ceiling is gone (d-2b4c96a2)","a rejected alternative of three words or fewer becomes a name the check enforces; write it as a sentence when the word is in ordinary use (d-7c0ecc04)","a rejected name sat in a concept's related list after its concept was renamed (d-572be38e)","new nouns were left undeclared because the lexicon was outside the work order's write scope; escalate rather than leave them (u-de8416b2)"],"results":{"1":{"result":"skipped","because":"no definition's first sentence changed; one property of defect moved from class to family"},"2":{"result":"skipped","because":"no concept protected"},"3":{"result":"skipped","because":"no reject or rename"},"4":{"result":"done"},"5":{"result":"skipped","because":"no new noun"},"6":{"result":"done"},"7":{"result":"skipped","because":"no rename"},"8":{"result":"done","evidence":"lexicon --check: 0 rejected names, 0 unknown nouns"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.e2324353.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.e2324353.jsonl new file mode 100644 index 00000000..eb371494 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.e2324353.jsonl @@ -0,0 +1,36 @@ +{"id":"d-a59ee38f","kind":"decision","at":"2026-10-27T16:04:03.672Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"remove the hand-written reader slots (source, declares, topLevel, kept) from the plugin interface: pluginApi 4, a plugin of any version that fills one is refused naming the slot and the treeSitter way to read the language, and the core keeps one reader per language","over":["deprecate them first: keep them loading with a warning at session start and in plugin check until a later interface version refuses them"],"because":"nothing but the test fixtures fills them (the four bundled language plugins and mnemion's Swift plugin all read through treeSitter), so a deprecation period protects no one, and two readers of one language are a shape the core should not be able to express","human":"maybe we just kill the hand written slots altogether to force migration. it's a quick task for an agent","binding":"none: this session owns no active work order"} +{"id":"d-2dfb13fc","kind":"decision","at":"2026-10-27T16:15:31.911Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"correct d-354e6716: the amendment of close a defect also adds the explicit trigger, so a code review answered without a recorded defect still delivers it, and widens the guard step's decision to a bug only time or a scheduler can show, bounded structurally; its summary now names the two ways the resolved verb accepts, a guard (at best a fix that leaves the code no way to express the class) or a decision; and the pitfall no longer counts the store's file system calls, a number no record held","over":["leave d-354e6716 saying each step still asks what it asked"],"because":"the blind review of 887abd8 found the record understated the change, the summary offered a close the verb does not take, and the count of 35 calls had no source","cites":["d-354e6716"],"binding":"none: this session owns no active work order"} +{"id":"d-e52e4145","kind":"decision","at":"2026-10-27T16:15:32.196Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"df-194f5620 stays recorded in class path-identity beside df-7c50adfe, and its guard failure stands as a real repeat: both are Coherence following a symbolic link a repository controls, the store's writes then and the warm-up's reads now","over":["declare a class for a followed link and classify both defects into it, which leaves the repeat a repeat; or classify df-194f5620 elsewhere, which hides it"],"because":"the class's definition (one file spelled two ways) is narrower than both defects, as the review of 887abd8 found, but the shape the two share is the same, the guard of the first covered the store alone, and the warm-up's reads, and every enumeration of the project, are now held by their own invariants (src/plugins/a repository cannot stop a warm-up or speak through the store, src/adapters/a reading is handed only files it can open); whether to declare the narrower class is the owner's","cites":["df-194f5620","df-7c50adfe"],"binding":"none: this session owns no active work order"} +{"id":"df-a5d052ce","kind":"defect","at":"2026-10-27T16:25:46.908Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"what":"every short process that parsed anything loaded the whole parse store and its log at exit, so a committed 64 MB log of newlines, each passed over free, held mass 9 s and a hook past its budget: flush loaded the store to tag its lines with a generation it had verified","evidence":"blind review of 887abd8 (review5/store, review5/claims): probes/hook.mjs, mass 9.21 s at 887abd8 against 0.32 s at b19875c on a 2-file project with a 64 MB log of newlines; 340 ms at exit over a real 72 MB store","files":[],"class":"cost","introduced":"887abd8","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-1d7ca136","kind":"resolution","at":"2026-10-27T16:25:47.576Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"of":"df-a5d052ce","because":"flush tags its lines with the generation it trusted, or the one the store's first line names where it never loaded the store, which admits nothing since a reader reads only lines of the generation it verified itself; an empty log line counts torn like any other; the long-lived test asserts a process that parses and appends loads the store zero times","guard":"src/plugins/a long-lived process reads what other processes did","binding":"none: this session owns no active work order"} +{"id":"df-586f6367","kind":"defect","at":"2026-10-27T16:25:47.852Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"what":"the parse-based tests that held the store's structural claims passed second doors spelled in ordinary TypeScript: an aliased or destructured file system call, the folder held under another name, Object.assign onto this, this[...] and call recursion, mutual recursion, a class nested in StoreFolder, parsesFolder called from another own holder","evidence":"blind review of 887abd8 (review5/store, review5/claims): patches b1..b14 and t1..t10, each green on the 20 tests at 887abd8","files":[],"class":"over-claim","introduced":"887abd8","caught":"review","binding":"none: this session owns no active work order"} +{"id":"df-c0ff2e33","kind":"defect","at":"2026-10-27T16:25:58.178Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"what":"the prerelease script guarded the working tree's untracked files, not what ships: it refused over symlinks git does not ignore and none ships, cut with ignored files npm pack ships, left main stale under a remote set to fetch fewer branches, matched any host ending in github.com, and passed over a manifest that did not read","evidence":"blind review of 887abd8 (review5/store, review5/claims): tools/probe.ts, prereleaseProblems() empty with __pycache__ and a .tgz ignored in plugins/ that npm pack --dry-run lists, and after git remote set-branches origin beta with main moved on","files":[],"class":"over-claim","introduced":"887abd8","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-167d0c1f","kind":"resolution","at":"2026-10-27T16:25:58.810Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"of":"df-c0ff2e33","because":"the tarball is packed from a fresh clone of the commit released, installed and built there, so nothing of the working tree can ship; branches are fetched by an explicit refspec; GitHub is matched by its own host alone; an unreadable or versionless manifest is refused","guard":"src/lifecycle/a prerelease carries main","binding":"none: this session owns no active work order"} +{"id":"df-31037d28","kind":"defect","at":"2026-10-27T16:25:59.086Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"what":"an empty or relative HOME put Coherence's user folder, and the machine key that signs kept parses, under the current folder, so a repository holding the key such a process signed with fed its own store to the readings","evidence":"blind review of 887abd8 (review5/store, review5/claims): probes/forge.mjs, HOME=\"\" XDG_CONFIG_HOME=\"\" in a project holding .config/coherence/parses.key and a store signed with it: import os read as FORGED_MODULE","files":[],"class":"over-claim","introduced":"887abd8","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-38efbb68","kind":"resolution","at":"2026-10-27T16:25:59.705Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"of":"df-31037d28","because":"the home is HOME where it is absolute, else the account's own from the user database, else a folder of the user's own in the system's temporary folder, never a relative path","guard":"src/lifecycle/Coherence's own folder is absolute","binding":"none: this session owns no active work order"} +{"id":"df-6390e728","kind":"defect","at":"2026-10-27T16:25:59.974Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"what":"the amended kernel practice close a defect said a defect closes when the code can no longer express its class, a close the resolved verb does not take, and claimed a guard seen to fire for a close by decision","evidence":"blind review of 887abd8 (review5/store, review5/claims): Journal.practice.md:1 against resolved's --guard or --decision (Journal.spec.md:215)","files":[],"class":"audience","introduced":"887abd8","caught":"review","binding":"none: this session owns no active work order"} +{"id":"d-fd419a99","kind":"decision","at":"2026-10-27T16:26:00.263Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"close a defect's summary names the two closes the resolved verb takes, a guard (at best a fix that leaves the code no way to express the class) or a decision, and the fix itself is a step","over":["make a structural fix a third kind of close the verb accepts"],"because":"a structural fix counts only through the invariant that holds it, which is a guard; a third kind would let a close name no witnessed refutation, which the defect floor exists to refuse","binding":"none: this session owns no active work order"} +{"id":"rs-f21de0b7","kind":"resolution","at":"2026-10-27T16:26:00.540Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"of":"df-6390e728","because":"the summary now reads that a defect closes when a guard covers its whole class, at best a fix that leaves the code no way to express it, held by an invariant seen to fire, or when a decision says why fixing the instance suffices (d-2dfb13fc)","decision":"d-fd419a99","binding":"none: this session owns no active work order"} +{"id":"rs-4293617f","kind":"resolution","at":"2026-10-27T16:26:01.150Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"of":"df-586f6367","because":"the tests now refuse every such spelling the parse can see (a name of node:fs only ever called, a fixed set of system modules, no eval, Function, this[...], Object.assign(this), pattern out of or into this, nested class, no function of the module reaching itself again through any other, parsesFolder and newGeneration only called where they belong, and ParseStore's every folder call one fixed list); 22 of the review's 24 patches turn a test red, the other two no longer apply; a name built at run time is beyond a parse, and the bullet says so","guard":"src/plugins/the parse store touches its files only through StoreFolder","binding":"none: this session owns no active work order"} +{"id":"d-e8f43329","kind":"decision","at":"2026-10-27T16:49:05.675Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"correct d-6b0fbea9 and df-467db56c's numbers: around a parenthesized import type the patched TypeScript grammar can read a whole file as one error at its root and lose every declaration in it, those before the import type included; over about 106,000 node_modules files 12 read 19 declarations fewer than stock, and the plugin guide says so","over":["leave the guide saying the grammar recovers less of what follows, 4 declarations over 80,000 files"],"because":"the blind review of 887abd8 cut remark-rehype's index.d.ts to its lines 1-7 and 30-40: stock reads HastRoot, MdastRoot, Options and Processor, the bundled grammar reads none, its root an ERROR rather than program; the choice d-6b0fbea9 made stands, since tsc refuses none of these files and PostHog loses none","cites":["d-6b0fbea9","df-467db56c"],"binding":"none: this session owns no active work order"} +{"id":"df-ec8b00ec","kind":"defect","at":"2026-10-27T16:51:44.025Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"what":"the test that every TypeScript operator is a node of its own spelling read a sample text holding 74 of the TSX grammar's 143 anonymous symbols, so a build aliasing @ as string_fragment, as & had been, passed it","evidence":"blind review of 887abd8 (review5/grammar): probe/cover.mjs; a TSX build with alias(token.immediate('@'), $.string_fragment) read every decorator @ as string_fragment with the test green","files":[],"class":"over-claim","introduced":"887abd8","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-dd758ef7","kind":"resolution","at":"2026-10-27T16:51:44.667Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"of":"df-ec8b00ec","because":"the test reads every anonymous symbol of each grammar's own table and asks the grammar for it by its spelling; a scratch build aliasing @ goes red","guard":"src/plugins/the TypeScript parsers read what their release cannot","binding":"none: this session owns no active work order"} +{"id":"df-8dfa4edc","kind":"defect","at":"2026-10-27T16:51:44.938Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"what":"the test holding build.sh and CI matched their text, so a fetch that only warned, a final comparison replaced by true, the compiler's paths unset, an unpinned clone or fetch, the CI step skipped, verify not run always, and verify's loop exiting 0 each kept it green","evidence":"blind review of 887abd8 (review5/grammar): repo-tamper, all eight edits at once, the test ok","files":[],"class":"over-claim","introduced":"887abd8","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-b12ca6be","kind":"resolution","at":"2026-10-27T16:51:45.560Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"of":"df-8dfa4edc","because":"the test now holds what each check does on failure: set -eu first, nothing excusing a failure or unsetting a pin, fetch exiting on a digest that differs, the network reached for the pinned releases and upstream alone, the upstream checked out at its hash, the bundled parsers written only after every digest compares and exits otherwise, the CI job unconditional, verify run always and failing on any need that did not succeed; each of the eight edits goes red","guard":"src/plugins/the TypeScript parsers are the ones their build makes","binding":"none: this session owns no active work order"} +{"id":"df-9a665518","kind":"defect","at":"2026-10-27T16:51:45.835Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"what":"a tracked symbolic link relinked to another folder, or left dangling, dropped out of the working change: keepProjectFiles refused every path a reading could not open, a link to a folder or to nothing among them","evidence":"blind review of 887abd8 (review5/grammar): economy src/a.ts --changed read 3 changed paths where git status showed 5, linkdir and src/link.ts gone","files":[],"class":"silent-skip","introduced":"887abd8","caught":"review","binding":"none: this session owns no active work order"} +{"id":"rs-d36e8302","kind":"resolution","at":"2026-10-27T16:51:46.452Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"of":"df-9a665518","because":"a change keeps every path it names but a folder, a pipe, a socket, a device or a link to one of those; a tracked link relinked or dangling, and a deleted file, stay changed paths; the economy reading of the reviewer's repository names linkdir and src/link.ts again","guard":"src/adapters/a reading is handed only files it can open","binding":"none: this session owns no active work order"} +{"id":"en-a4aad046","kind":"enactment","at":"2026-10-27T16:58:30.678Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/journal/close a defect","version":"334a8cbb","trigger":"command cli.* defect","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"name what let the bug be written (the state a value can hold that it never should, or a second way to do what one function should do alone), then sweep the codebase for every sibling of that shape and record the sweep: what was searched and each sibling found, or that it found none","leaves":"the representable shape, and the sweep"},{"text":"fix it so the code cannot express it again, in preference to a check at the site: one door every caller must pass (a function or class its module keeps private, so the compiler, or a totality oracle where the language has no such check, refuses any other caller), a type that cannot hold the bad value, a walk with a stack of its own rather than recursion over what input controls, a fact derived where it is needed rather than kept twice; route every sibling the sweep found through it","leaves":"the door, type or derivation, and the siblings now routed through it"},{"text":"guard or decide: name an invariant that fails on any second way to write the bug, a chokepoint the compiler grades or a totality oracle that reads the code and refuses each other door (another call, a name held under an alias, a module asked for by string), adding the bullet when none exists; or record a decision saying why fixing the instance suffices, or that only time or a scheduler can show the bug (a cost, a race), bounding it structurally all the same (a size every read passes, a lock only one process can take)","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a second way to write the bug rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)","the parse store's defences were checks written at each of its file system calls, and three blind reviews in a row found one more call without its check; one gateway, unexported and held by a parse of its module, was the fix that held (ca263d3, df-8b32c22b)","the gateway's totality oracle read only node:fs imported by name, so a require made with createRequire and the file system asked of process.getBuiltinModule each wrote past it with the test green (df-69c8ab4d)","a recursion over a parse tree was kept when its function was rewritten, so a file nested deep enough crashed every reading (df-6e6c2b80)"],"results":{"1":{"result":"done","evidence":"df-a5d052ce df-586f6367 df-c0ff2e33 df-31037d28 df-6390e728 df-ec8b00ec df-8dfa4edc df-9a665518, each with --class, --introduced 887abd8 and --caught review"},"2":{"result":"done","evidence":"each names its representable shape (a load at exit, second doors in ordinary TypeScript, a sampled token text, text-matched build checks, a change filtered by readability, a tarball packed from the working tree, a relative HOME, a summary naming a close the verb lacks); the sweeps: every patch the store review staged, every anonymous symbol of both grammars, every tampering of build.sh and ci.yml, the economy reading of the reviewer's repository"},"3":{"result":"done","evidence":"a tarball packed from a clone of the commit, so nothing of the working tree can ship; one symbol table read whole; the home chosen only among absolute paths; ParseStore's folder calls one fixed list"},"4":{"result":"done","evidence":"guards src/plugins/a long-lived process reads what other processes did, the parse store touches its files only through StoreFolder, the TypeScript parsers read what their release cannot, the TypeScript parsers are the ones their build makes, src/adapters/a reading is handed only files it can open, src/lifecycle/a prerelease carries main, Coherence's own folder is absolute; decision d-fd419a99; the audit's bound stays under d-05717677"},"5":{"result":"done","evidence":"refute runs recorded for each guard's break (the @ build, fetch warning, CI step skipped, change dropping links, the clone pack, the refspec, the host, the manifest, HOME); 22 of 24 review patches red"},"6":{"result":"done","evidence":"resolutions rs-1d7ca136 rs-4293617f rs-167d0c1f rs-38efbb68 rs-f21de0b7 rs-dd758ef7 rs-b12ca6be rs-d36e8302; spec --check 0 problems"}},"binding":"none: this session owns no active work order"} +{"id":"en-29c5630d","kind":"enactment","at":"2026-10-27T16:58:31.286Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"the touched bullets green in the full suite before each break"},"2":{"result":"done","evidence":"each break the smallest change of the claimed behaviour, asserted to match once"},"3":{"result":"done","evidence":"refute --broke with the break staged, for each new claim; the store review's patches staged by script against syntax-trees.test.ts"},"4":{"result":"done","evidence":"each file restored from a copy and compared byte for byte"},"5":{"result":"done","evidence":"run --each over the eleven touched bullets, 12 enforcements pass batched, 11 alone"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} +{"id":"d-d1229127","kind":"decision","at":"2026-10-27T17:39:47.991Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"keep kept parses in a per-user cache outside every project, content-addressed by the parser's fingerprint and the text's digest, written once in whole segment files and never modified; drop the in-project store, its signing, generations, log, reload and the hostile-folder defenses it needed","over":["keep the store in .coherence/parses and keep adding defenses at each site a review finds"],"because":"four rounds of blind review found about 30 defects in the in-project store, each round's local fixes adding surface the next round broke: the store shared the untrusted repository's namespace and was mutable shared state, while a parse is a pure function of its text and fingerprint","human":"the parse cache definitely does not need to live in the project. implement your proposed fixes as part of this pending PR","binding":"none: this session owns no active work order"} +{"id":"en-6e101446","kind":"enactment","at":"2026-10-27T17:47:47.891Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/journal/close a defect","version":"334a8cbb","trigger":"command cli.* defect","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"name what let the bug be written (the state a value can hold that it never should, or a second way to do what one function should do alone), then sweep the codebase for every sibling of that shape and record the sweep: what was searched and each sibling found, or that it found none","leaves":"the representable shape, and the sweep"},{"text":"fix it so the code cannot express it again, in preference to a check at the site: one door every caller must pass (a function or class its module keeps private, so the compiler, or a totality oracle where the language has no such check, refuses any other caller), a type that cannot hold the bad value, a walk with a stack of its own rather than recursion over what input controls, a fact derived where it is needed rather than kept twice; route every sibling the sweep found through it","leaves":"the door, type or derivation, and the siblings now routed through it"},{"text":"guard or decide: name an invariant that fails on any second way to write the bug, a chokepoint the compiler grades or a totality oracle that reads the code and refuses each other door (another call, a name held under an alias, a module asked for by string), adding the bullet when none exists; or record a decision saying why fixing the instance suffices, or that only time or a scheduler can show the bug (a cost, a race), bounding it structurally all the same (a size every read passes, a lock only one process can take)","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a second way to write the bug rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)","the parse store's defences were checks written at each of its file system calls, and three blind reviews in a row found one more call without its check; one gateway, unexported and held by a parse of its module, was the fix that held (ca263d3, df-8b32c22b)","the gateway's totality oracle read only node:fs imported by name, so a require made with createRequire and the file system asked of process.getBuiltinModule each wrote past it with the test green (df-69c8ab4d)","a recursion over a parse tree was kept when its function was rewritten, so a file nested deep enough crashed every reading (df-6e6c2b80)"],"results":{"1":{"result":"skipped","because":"fired by the dead-end alarm subagent's defect commands in its own worktree (coherence-alarm), which records its own records; this session closed no defect there"},"2":{"result":"skipped","because":"fired by the dead-end alarm subagent's defect commands in its own worktree (coherence-alarm), which records its own records; this session closed no defect there"},"3":{"result":"skipped","because":"fired by the dead-end alarm subagent's defect commands in its own worktree (coherence-alarm), which records its own records; this session closed no defect there"},"4":{"result":"skipped","because":"fired by the dead-end alarm subagent's defect commands in its own worktree (coherence-alarm), which records its own records; this session closed no defect there"},"5":{"result":"skipped","because":"fired by the dead-end alarm subagent's defect commands in its own worktree (coherence-alarm), which records its own records; this session closed no defect there"},"6":{"result":"skipped","because":"fired by the dead-end alarm subagent's defect commands in its own worktree (coherence-alarm), which records its own records; this session closed no defect there"}},"binding":"none: this session owns no active work order"} +{"id":"en-5e07268a","kind":"enactment","at":"2026-10-27T17:51:30.174Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"skipped","because":"fired by the release-in-CI subagent's refute in its own worktree (coherence-release-ci), whose refutations it witnesses and reports itself; this session staged no break there"},"2":{"result":"skipped","because":"fired by the release-in-CI subagent's refute in its own worktree (coherence-release-ci), whose refutations it witnesses and reports itself; this session staged no break there"},"3":{"result":"skipped","because":"fired by the release-in-CI subagent's refute in its own worktree (coherence-release-ci), whose refutations it witnesses and reports itself; this session staged no break there"},"4":{"result":"skipped","because":"fired by the release-in-CI subagent's refute in its own worktree (coherence-release-ci), whose refutations it witnesses and reports itself; this session staged no break there"},"5":{"result":"skipped","because":"fired by the release-in-CI subagent's refute in its own worktree (coherence-release-ci), whose refutations it witnesses and reports itself; this session staged no break there"},"6":{"result":"skipped","because":"fired by the release-in-CI subagent's refute in its own worktree (coherence-release-ci), whose refutations it witnesses and reports itself; this session staged no break there"}},"binding":"none: this session owns no active work order"} +{"id":"d-fd38bffc","kind":"decision","at":"2026-10-27T17:53:14.312Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"add the kernel practice keep state where it is true, distilled from Data is destiny, in src/journal/Journal.practice.md beside close a defect, fired on demand and on recording a defect, its pitfalls citing Coherence's own records; a trigger by defect class comes with the dead-end alarm","over":["fire it on a change that adds state, which no command or edit trigger can say for every adopter's language; or file it with the specs"],"because":"every recurring fault this session came from state kept in two places, kept where an untrusted party writes, or an output not a function of its data; the owner accepted the recommendations","human":"accept your recommendations","binding":"none: this session owns no active work order"} +{"id":"d-ab934293","kind":"decision","at":"2026-10-27T17:54:49.180Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"demote src/plugins/a store's log costs a repository nothing and lies to no reading: retired, the code changed: the parse store keeps no log and no file of a project's, so no repository's log can cost or feed a reading; what it guarded is held by src/plugins/the parse store never reaches past the project's own folders","over":[],"because":"the parse store moved to the user's cache, its segments written once (d-d1229127); a project's .coherence/parses, a planted log among it, is never read, which that bullet's test shows","cites":["d-d1229127"],"binding":"none: this session owns no active work order"} +{"id":"d-8aa2df3f","kind":"decision","at":"2026-10-27T17:54:49.475Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"demote src/plugins/a store's generation changes only where it is rewritten: retired, the code changed: the store has no generation, its segments are written once and never changed, and a reader that finds a segment it read gone reads again; what it guarded is held by src/plugins/a long-lived process reads what other processes did","over":[],"because":"a generation existed only to tell a reader that a mutable store had been rewritten or discarded under it; with immutable segments there is nothing to tell (d-d1229127)","cites":["d-d1229127"],"binding":"none: this session owns no active work order"} +{"id":"en-c940fd6a","kind":"enactment","at":"2026-10-27T18:00:42.166Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/journal/keep state where it is true","version":"55aa82c8","trigger":"explicit","steps":[{"text":"name the state the change touches: each truth (what is observed, entered or decided) and each value derived from one (a count, a cache, an index, a copy, a version repeated across files, a number written in a document)","leaves":"the truths and the derivations, each derivation naming the truth it comes from"},{"text":"store each truth once: where a second copy exists, compute it from the first (when built, read or shown) or remove it; a copy that must be kept (a cache, a snapshot) is filed by the truth it came from, by its digest or fingerprint, so it cannot disagree without being read as another","leaves":"each truth's one home, and each derivation's function or key"},{"text":"choose where state lives by who may write it and how long it lives: never where a party you do not trust can write (a tool's cache inside the project it reads), never a file two processes change in place; prefer records written once, whole, and never changed, over a file edited in turn","leaves":"each store's location, who may write it, and whether anything in it changes once written"},{"text":"make every output a function of the state: the same data gives the same answer whatever the time, the load, or what a process did before; where a reading must stop early (a time budget), it stops by what it counted and names what it did not read","leaves":"each output's inputs, and each place it can differ on the same data, removed or named"},{"text":"hold it with an invariant that recomputes each kept derivation from its truth and fails on a difference, or fails where a second writer of a truth appears; and record the choice of each store's home as a decision","leaves":"the invariant's / and its refutation, and the decision's id"}],"pitfalls":["Coherence kept its parse cache inside each project it read, so a repository could write the cache's files, and four rounds of blind review found about thirty defects in its defences; moved to the user's own cache, filed by the text's digest and written once, the defences were no longer needed (d-d1229127)","one version was kept in eight files, the package's and seven plugin manifests, and a prerelease checked them against each other because nothing derived them (df-089ac5a9, w-d112a3e4)","a journal kept per worktree showed one copy of a session's records, and the pane that read it showed nearly none (w-4c76c5ea)","numbers typed into documents and decisions from a measurement went stale or wrong, and had to be corrected by later decisions (d-2dfb13fc, d-e8f43329)","a reading stopped by a time budget gave different answers on the same checkout under different machine load (w-77d2fe8f)"],"results":{"1":{"result":"done","evidence":"truths: each source text, and the parser's inputs (fingerprintOf); derivations: each kept parse, a function of a text and a fingerprint; the stale-store audit"},"2":{"result":"done","evidence":"a kept parse is stored once, filed by the text's digest under the fingerprint, in one store every project and worktree shares; the per-project stores and registry roots (storeRootOf) are gone"},"3":{"result":"done","evidence":"the store lives in the user's cache, used only where it is the user's alone (ownFolder), in segments written once, whole, never changed; nothing of a project's is read or written (d-d1229127)"},"4":{"result":"done","evidence":"a reader's answers are a function of the segments present: it rereads when one it read is gone, and a short process writes without reading; the structure reading's time budget, which is not a function of its data, is w-77d2fe8f"},"5":{"result":"done","evidence":"src/plugins/the parse store never reaches past the project's own folders, a long-lived process reads what other processes did, a warm-up keeps the store small and runs once per project, each refuted through refute; d-d1229127, d-ab934293, d-8aa2df3f"}},"binding":"none: this session owns no active work order"} +{"id":"en-609df1d8","kind":"enactment","at":"2026-10-27T18:00:42.781Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/journal/close a defect","version":"334a8cbb","trigger":"command resolved df-*","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"name what let the bug be written (the state a value can hold that it never should, or a second way to do what one function should do alone), then sweep the codebase for every sibling of that shape and record the sweep: what was searched and each sibling found, or that it found none","leaves":"the representable shape, and the sweep"},{"text":"fix it so the code cannot express it again, in preference to a check at the site: one door every caller must pass (a function or class its module keeps private, so the compiler, or a totality oracle where the language has no such check, refuses any other caller), a type that cannot hold the bad value, a walk with a stack of its own rather than recursion over what input controls, a fact derived where it is needed rather than kept twice; route every sibling the sweep found through it","leaves":"the door, type or derivation, and the siblings now routed through it"},{"text":"guard or decide: name an invariant that fails on any second way to write the bug, a chokepoint the compiler grades or a totality oracle that reads the code and refuses each other door (another call, a name held under an alias, a module asked for by string), adding the bullet when none exists; or record a decision saying why fixing the instance suffices, or that only time or a scheduler can show the bug (a cost, a race), bounding it structurally all the same (a size every read passes, a lock only one process can take)","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a second way to write the bug rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)","the parse store's defences were checks written at each of its file system calls, and three blind reviews in a row found one more call without its check; one gateway, unexported and held by a parse of its module, was the fix that held (ca263d3, df-8b32c22b)","the gateway's totality oracle read only node:fs imported by name, so a require made with createRequire and the file system asked of process.getBuiltinModule each wrote past it with the test green (df-69c8ab4d)","a recursion over a parse tree was kept when its function was rewritten, so a file nested deep enough crashed every reading (df-6e6c2b80)"],"results":{"1":{"result":"skipped","because":"no defect recorded; df-04fddaf1's guard was retired with the in-project store"},"2":{"result":"skipped","because":"no new shape"},"3":{"result":"done","evidence":"the store moved out of every project, so a project's log can no longer be read (d-d1229127)"},"4":{"result":"deviated","because":"resolved refused to close df-04fddaf1 again under src/plugins/the parse store never reaches past the project's own folders; the gap is w-fdc00207, and d-ab934293 names that guard"},"5":{"result":"done","evidence":"the new guard refuted through refute (a cache whoever may write it used)"},"6":{"result":"deviated","because":"spec --check names df-04fddaf1 as a close with neither until w-fdc00207 lets it be closed again"}},"binding":"none: this session owns no active work order"} +{"id":"d-1ed232b8","kind":"decision","at":"2026-10-27T18:07:41.359Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"chose":"amend src/journal/close a defect: step 3 now adds that, when the dead-end reading names the defect's component, a different design is weighed before a narrower door in the same one, and the choice is recorded as a decision (d-0f7f9434)","over":["keep step 3 as en-609df1d8 enacted it"],"because":"the owner asked for an alarm for agentic dead ends and its guidance in the practice; the step still asks for the fix that leaves the bug inexpressible, now naming the redesign the alarm points to","cites":["en-609df1d8"],"binding":"none: this session owns no active work order"} +{"id":"en-e1a63f35","kind":"enactment","at":"2026-10-27T18:08:13.590Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/lifecycle/settle a domain term","version":"f51dc0a6","trigger":"command lexicon propose","steps":[{"text":"read the term's live uses before naming it: coherence lexicon review "},{"text":"decide what it is: the project's own concept, an alias of one, a property of one (a field, a column, a unit), or an ordinary programming word that needs no entry"},{"text":"settle a contested term from the project's own history (commit messages, pull request discussion) and record the tie-break with decide","leaves":"the decision's id"},{"text":"when the history does not settle it, escalate instead of deciding: two live senses that no record separates, the owner's word colliding with a name the lexicon rejected, or any rename, retire, reject or lift of a concept; carry on with the term provisional, and apply only with the human's words","leaves":"the escalation's id"},{"text":"before rejecting a name, count the findings it would create; a word in ordinary use gets a qualifying rename, not a bare rejection"},{"text":"propose, then apply with because and over; a human ruling carries the human's words with --human, and none is ever invented"},{"text":"run coherence lexicon --check","leaves":"0 rejected names and 0 unknown nouns beyond the baseline"}],"pitfalls":["rejecting a bare word turned 227 uses of a language keyword into findings (rt-cdcf2a29)","field and column names were nominated as unknown nouns until they were filed as properties of their concepts (d-3283157b)","identifiers written in backticks in specs were nominated as unknown nouns (d-9e7b9247)","common programming words kept as rejected names made hundreds of findings in ordinary code (d-f77ce193)","the owner's own word for a thing collided with a name the lexicon had rejected for another concept (c-c05b409e)","new nouns were left undeclared because the lexicon was outside the session's scope, where an escalation would have reached the owner (u-de8416b2)"],"results":{"1":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f); merged here as its records"},"2":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f); merged here as its records"},"3":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f); merged here as its records"},"4":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f); merged here as its records"},"5":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f); merged here as its records"},"6":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f); merged here as its records"},"7":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f); merged here as its records"}},"binding":"none: this session owns no active work order"} +{"id":"en-37c3264f","kind":"enactment","at":"2026-10-27T18:08:16.435Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"the store bullets green in the store tests before each break"},"2":{"result":"done","evidence":"eight breaks, each the smallest change of a claimed behaviour (no segment written, a stale store left, a cache of anyone's used, any file size read, removed segments still answering, parsesFolder exported, a leaf warmed alone, no merge), each asserted to match once"},"3":{"result":"done","evidence":"refute --broke for each of the eight, each red on its own assertion"},"4":{"result":"done","evidence":"each file restored from a copy and compared byte for byte"},"5":{"result":"deviated","because":"run --each over the eleven bullets: 12 enforcements pass batched, one failed alone because it read segments an earlier test left; the test now writes its own and passes alone twice"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} +{"id":"en-7c144769","kind":"enactment","at":"2026-10-27T18:08:32.622Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/lifecycle/carry a lexicon change through","version":"f28a1b08","trigger":"command lexicon apply","steps":[{"text":"write the first sentence as the definition a session needs at a glance; the lexicon has no token ceiling; the start injection presents at most 2,000 tokens of it and decays the least recently named concepts to fit (d-2b4c96a2, d-f0da2f1f)"},{"text":"mark a concept \"protected\": true only when a human asks for it to stay whole however long the journal goes without naming it"},{"text":"before a reject or a rename, count the findings it would create across the corpus; a word in ordinary use or a language keyword gets a qualifying rename instead of a bare rejection"},{"text":"propose, then apply with because and over; a human ruling carries the human's words with --human, and none is ever invented"},{"text":"declare a new noun before any code, spec, or record uses it"},{"text":"update every concept whose definition or related list names the changed one"},{"text":"rename once, everywhere: files, commands, modules, Scope views, npm scripts, and refuse the old name with a one-line migration"},{"text":"run the vocabulary check","leaves":"lexicon check with 0 rejected names and 0 unknown nouns"}],"pitfalls":["rejecting a bare word turned 227 uses of the TypeScript keyword into findings (d-5060eaab, rt-cdcf2a29)","a fixed token ceiling was crossed and trimmed afterwards three times, and once its test was already red for the next session (d-3eb04416, d-7f5b5203, d-beedd69e, u-1c5215fe); the ceiling is gone (d-2b4c96a2)","a rejected alternative of three words or fewer becomes a name the check enforces; write it as a sentence when the word is in ordinary use (d-7c0ecc04)","a rejected name sat in a concept's related list after its concept was renamed (d-572be38e)","new nouns were left undeclared because the lexicon was outside the work order's write scope; escalate rather than leave them (u-de8416b2)"],"results":{"1":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f)"},"2":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f)"},"3":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f)"},"4":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f)"},"5":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f)"},"6":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f)"},"7":{"result":"skipped","because":"fired by the dead-end alarm subagent's lexicon change in its own worktree (coherence-alarm), which it carried out and recorded under its own session (en-62da35fa, en-6ca296c7, en-d4d054c9; d-d5bea2db, d-b66f940f)"},"8":{"result":"done","evidence":"npm run -s lexicon:check on the merged tree: 0 rejected names, 0 unknown nouns (631 files)"}},"binding":"none: this session owns no active work order"} +{"id":"en-547c6229","kind":"enactment","at":"2026-10-27T18:22:23.266Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"skipped","because":"the refutes since the last enactment are the grammar subagent's, staged in its own worktree (coherence-grammar-diff) and recorded under its session as en-f7f06d2f; its run records are merged here"},"2":{"result":"skipped","because":"the refutes since the last enactment are the grammar subagent's, staged in its own worktree (coherence-grammar-diff) and recorded under its session as en-f7f06d2f; its run records are merged here"},"3":{"result":"skipped","because":"the refutes since the last enactment are the grammar subagent's, staged in its own worktree (coherence-grammar-diff) and recorded under its session as en-f7f06d2f; its run records are merged here"},"4":{"result":"skipped","because":"the refutes since the last enactment are the grammar subagent's, staged in its own worktree (coherence-grammar-diff) and recorded under its session as en-f7f06d2f; its run records are merged here"},"5":{"result":"deviated","because":"the batched and alone run over every touched bullet on the merged tree is running now, its results to be read before any commit"},"6":{"result":"skipped","because":"the refutes since the last enactment are the grammar subagent's, staged in its own worktree (coherence-grammar-diff) and recorded under its session as en-f7f06d2f; its run records are merged here"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.e28d93a5.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.e28d93a5.jsonl new file mode 100644 index 00000000..aee78e66 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.e28d93a5.jsonl @@ -0,0 +1,2 @@ +{"id":"en-3fedd5ce","kind":"enactment","at":"2026-10-26T22:12:38.664Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"a text reading is held to the language server's account\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.19edb05b.jsonl: pass batched and alone"},"2":{"result":"done","evidence":"one condition in serverAgrees made && false; diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.19edb05b.jsonl; confirmed by node --test on answers-agree.test.ts's own AssertionError (actual pass)"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/check.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.19edb05b.jsonl: pass batched, refutation witnessed, and alone"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} +{"id":"en-9429d9e8","kind":"enactment","at":"2026-10-26T22:12:39.029Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"plugin calibrate counts misreads and what the server alone reports\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.19edb05b.jsonl: pass batched and alone"},"2":{"result":"done","evidence":"the agreed count made ; diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.19edb05b.jsonl; confirmed by node --test on"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/ true in calibrate|calibrate.test.ts's own AssertionError|calibrate.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.19edb05b.jsonl: pass batched, refutation witnessed, and alone"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.e748a035.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.e748a035.jsonl new file mode 100644 index 00000000..62de57ee --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.e748a035.jsonl @@ -0,0 +1 @@ +{"id":"en-5d8ffc59","kind":"enactment","at":"2026-10-26T22:20:46.499Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"870296d","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"every language plugin reads the reference project alike\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.4c25ed1a.jsonl: pass batched (23.4 s) and alone (23.6 s)"},"2":{"result":"done","evidence":"one line in referenceRelations, a relation with no import counted held; diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.4c25ed1a.jsonl; confirmed by node --test on reference.test.ts's own AssertionError"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/check.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.4c25ed1a.jsonl: pass batched (24.1 s), refutation witnessed, and alone (24.1 s)"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.ec51fbdc.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.ec51fbdc.jsonl new file mode 100644 index 00000000..8ce9f0ce --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.ec51fbdc.jsonl @@ -0,0 +1,2 @@ +{"id":"d-cb7829df","kind":"decision","at":"2026-10-26T20:51:26.357Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"46d80e0","dirty":true,"chose":"an import resolves to a module (its folder and files) where the language's module is several files, and the core joins each imported name to the files of it that declare the name, every file when the module is imported whole or no file declares the name; Go drops its path#Name specifiers for it","over":["each plugin picking one file of a module by a rule of its own","a whole-module import counted as one edge to the module's folder"],"because":"four plugins answered which file a module import reaches four ways (Go: the file declaring the name packed into the specifier, else the first; the three blind Swift plugins: the file declaring the most names used, the file named after the target, Store.swift) and c-38a1baae's test is answered by the blind run itself: Sources/Api/Render.swift uses Row from Row.swift and seal and secretColumns from Secrets.swift, and S1 reached only Secrets.swift while S2 and S3 reached only Row.swift, so every one-file rule missed a file the importer uses; joining by declared names needs no rule a plugin writes, and reads the same in every language","human":"the whole module import would create better consistency, yeah? ... do it","cites":["c-38a1baae"],"binding":"none: this session owns no active work order"} +{"id":"en-755d224c","kind":"enactment","at":"2026-10-26T20:54:00.372Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"46d80e0","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant \"an import of a module joins the files that declare what it imports\" --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.6c7e016d.jsonl: pass batched (22.5 s) and alone (22.7 s)"},"2":{"result":"done","evidence":"one line in importsOf, the files joined made files.slice(0, 1); diff read before the refute"},"3":{"result":"done","evidence":"refutation red recorded in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.6c7e016d.jsonl; confirmed by node --test --test-name-pattern on the test's own AssertionError (a name joins the file that declares it, and no other)"},"4":{"result":"done","evidence":"cmp against the copy taken before the break printed nothing (scratchpad pilot/copies/source.ts)"},"5":{"result":"done","evidence":"run --each in .coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.6c7e016d.jsonl: pass batched (23.4 s), refutation witnessed, and alone (23.2 s)"},"6":{"result":"skipped","because":"the red came from the break, seen on the test's own assertion"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.eec979c2.jsonl b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.eec979c2.jsonl new file mode 100644 index 00000000..f16e3226 --- /dev/null +++ b/.coherence/journal/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.eec979c2.jsonl @@ -0,0 +1,5 @@ +{"id":"df-fead3a57","kind":"defect","at":"2026-10-27T03:16:12.240Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c8c65e3","dirty":true,"what":"tree-sitter-typescript 0.23.2, the TypeScript plugin's two grammars, errs on an import type with type arguments or as an array's element (import('x').T, import('x').T[]), on a member named in_... after another member, and on a bare & in JSX, and its error recovery swallowed the declarations after some of them, so mass, interfaces and the spec checks lost names the hand-written reader had read","evidence":"battery on 1.11.0-beta.1 against main ec148c9: PostHog's frontend declarations 1734 on main, 1690 on beta.1 and on the alternate-parser fix; 64 of 5,832 files with a tree error; 25 lost in marketingAnalyticsLogic.ts, 18 in incidentStatusLogic.tsx, 1 in editorSceneLogic.tsx","files":[],"class":"parse-gap","introduced":"c30238c","caught":"probe","binding":"none: this session owns no active work order"} +{"id":"d-fd4e2e86","kind":"decision","at":"2026-10-27T03:16:12.500Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c8c65e3","dirty":true,"chose":"carry a patched build of tree-sitter-typescript 0.23.2 for both TypeScript parsers: grammars/tree-sitter-typescript holds the patch (import types as primary types with type arguments, identifier characters after in and instanceof in the semicolon scanner, a bare & as JSX text and string) and a script that rebuilds both parsers byte for byte","over":["waiting for upstream to release a fix | building from the open upstream fix #365 alone | offering the fixes upstream | only saying which files a parse could not read"],"because":"no newer grammar or maintained fork exists: upstream has merged no grammar change since 0.23.2 (2024-11) and Neovim, Helix, Zed, ast-grep and difftastic ship the same grammar; #365 parses 7 of PostHog's 64 erring files; the patch leaves one, recovers the 44 declarations lost and loses none in 5,832 files","human":"carry a patched grammar to fix this. feel free to install emscripten; decline to offer the fixes. waiting won't help and they're clearly checked out","cites":["d-b4fe6dee"],"binding":"none: this session owns no active work order"} +{"id":"rs-2e2eded0","kind":"resolution","at":"2026-10-27T03:18:42.956Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c8c65e3","dirty":true,"of":"df-fead3a57","because":"both TypeScript parsers are now tree-sitter-typescript 0.23.2 built with grammars/tree-sitter-typescript/coherence.patch (import types as primary types with type arguments, identifier characters after in and instanceof in the semicolon scanner, a bare & as JSX text and string); over PostHog's frontend the erring files go from 64 to 1 and the 44 lost declarations are read, none lost; sweep: the battery found no grammar error in Python, Go or Rust over PostHog, hexyl, hey and r-d-investigation","guard":"src/plugins/the TypeScript parsers read what their release cannot","binding":"none: this session owns no active work order"} +{"id":"en-bf674cf5","kind":"enactment","at":"2026-10-27T03:18:44.319Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c8c65e3","dirty":true,"practice":"src/journal/close a defect","version":"45e4c8e1","trigger":"resolved df-fead3a57","steps":[{"text":"classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect)","leaves":"the defect's or the classification's id"},{"text":"sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none","leaves":"the sweep: what was searched and each sibling found and fixed, or none"},{"text":"guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices","leaves":"the guard's / or the decision's id"},{"text":"refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance","leaves":"the refutation's run record"},{"text":"record the close: resolved --because \"\" with --guard / or --decision , then run spec --check","leaves":"the resolution's id; spec --check names no close with neither"}],"pitfalls":["the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f)","a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2)","an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f)"],"results":{"1":{"result":"done","evidence":"df-fead3a57, class parse-gap, caught probe (the battery)"},"2":{"result":"done","evidence":"the battery found no grammar error in Python, Go or Rust over its four projects; the one TypeScript file still erring loses no declaration"},"3":{"result":"done","evidence":"src/plugins/the TypeScript parsers read what their release cannot"},"4":{"result":"done","evidence":"stock parsers swapped in; over-eager scanner (each refuted, witnessed)"},"5":{"result":"done","evidence":"rs-2e2eded0; parse-gap is a family, so no guard failure"}},"binding":"none: this session owns no active work order"} +{"id":"en-9a5f953a","kind":"enactment","at":"2026-10-27T03:18:59.409Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"c8c65e3","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --each over the new bullet before breaking: it passed batched and alone with the patched parsers"},"2":{"result":"done","evidence":"two breaks: the stock 0.23.2 parsers swapped in (cmp-checked), and parsers built with a scanner that ends every line before in"},"3":{"result":"done","evidence":"refute went red on each, on the test's own assertions (import type with type arguments; the operator continuation)"},"4":{"result":"done","evidence":"each restored from copies (scratchpad patched-wasm), cmp byte for byte"},"5":{"result":"done","evidence":"run --each after: 1 pass batched, 1 alone, both refutations witnessed"},"6":{"result":"done","evidence":"both reds came from the breaks: each failure named the clause its break removed"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/a154667212a2ae093.792fcee3.jsonl b/.coherence/journal/a154667212a2ae093.792fcee3.jsonl new file mode 100644 index 00000000..6c4ab756 --- /dev/null +++ b/.coherence/journal/a154667212a2ae093.792fcee3.jsonl @@ -0,0 +1,3 @@ +{"id":"d-881c0b46","kind":"decision","at":"2026-10-27T16:23:40.908Z","session":"a154667212a2ae093","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"OLDEST_PLUGIN_API stays 1: plugins written for pluginApi 1 to 3 that fill none of source, declares, topLevel or kept keep loading, named at session start with what changed since","over":["moving OLDEST_PLUGIN_API to 4, which would refuse convex-like, quint-like and declared-like plugins that never filled a reader slot"],"because":"the refusal is by slot in the registry, whatever pluginApi a manifest names, so nothing an older plugin can still say is read twice; refusing whole versions would break plugins with no reader slot for no structural gain (w-8e253e9e)","binding":"none: this session owns no active work order"} +{"id":"d-581051d3","kind":"decision","at":"2026-10-27T16:23:41.174Z","session":"a154667212a2ae093","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"the core reads a language's text through parsedOf(language, source|declares|topLevel), derived from the parser alone, and syntaxOf answers only the five slots a plugin still fills; SourceSyntax lost declarationOf and left the plugin interface","over":["keeping syntaxOf answering the derived names through the parser, which would keep the four names typed as slots a plugin could name"],"because":"with the four out of SyntaxSlot and SyntaxTables the typecheck refuses any read of them as a slot, and the parse test in syntax-trees.test.ts refuses the shapes a cast could hide (close a defect: structurally unrepresentable)","binding":"none: this session owns no active work order"} +{"id":"d-cfc26b51","kind":"decision","at":"2026-10-27T16:23:41.434Z","session":"a154667212a2ae093","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"the bundled plugin manifests move to pluginApi 4","over":["leaving them at 3"],"because":"a project that names a bundled plugin in its config would otherwise be told at every session start that it was written for an older pluginApi","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/a3f414dba641b7895.5ef69790.jsonl b/.coherence/journal/a3f414dba641b7895.5ef69790.jsonl new file mode 100644 index 00000000..3193ace0 --- /dev/null +++ b/.coherence/journal/a3f414dba641b7895.5ef69790.jsonl @@ -0,0 +1,12 @@ +{"id":"d-960454ac","kind":"decision","at":"2026-10-27T18:16:25.857Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"compare the stock and patched TypeScript parsers through web-tree-sitter on the wasm each build makes, every node's type, named-ness, span, field and error status, in both dialects","over":["compare the native libraries' tree-sitter parse output, or read the patch's text"],"because":"the wasm is what Coherence ships and reads with, so the comparison reads the very parsers it vouches for, and its output, not the patch's text, is what a rename changes","binding":"none: this session owns no active work order"} +{"id":"d-46dd0b30","kind":"decision","at":"2026-10-27T18:16:26.482Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"a difference is the smallest run of sibling nodes outside which the two trees agree, allowed when an intended-differences.json entry of its kind (improvement, regression, both err, reshape) and dialect has a query capture the region overlaps, and each entry must show in every corpus case it names","over":["key intended differences by file and byte offset"],"because":"constructs and case names survive the corpus growing (this repository's src changes every commit), and an entry that no longer shows in its case fails, so the list holds no more than the patch does","binding":"none: this session owns no active work order"} +{"id":"d-cbb99f1b","kind":"decision","at":"2026-10-27T18:16:27.250Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"hold every token the patched parsers read to how the stock parsers read its spelling across the corpus: an anonymous leaf that is not its own spelling, or a named leaf spelled as a stock token, must be a pair the stock trees show, inside an improvement's region as anywhere","over":["key the token check on web-tree-sitter's grammarType"],"because":"a token used only under an alias takes the alias's name in its parser's table: keyof aliased as typeof reported grammarType typeof, so grammarType hid the very renames the check exists for; spelling does not move","binding":"none: this session owns no active work order"} +{"id":"d-a55de331","kind":"decision","at":"2026-10-27T18:16:27.848Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"let an intended entry list a token reading it brings (instanceof as property_identifier, for a member named instanceof), allowed only inside that entry's own regions and required to show there","over":["allow any keyword spelled as an identifier type, or no exception"],"because":"the real patch reads instanceof as a member name, which no stock tree in the corpus does, while a blanket allowance would let keyof read as an identifier pass inside a region","binding":"none: this session owns no active work order"} +{"id":"d-67fb163f","kind":"decision","at":"2026-10-27T18:16:28.273Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"the real-code corpus is TypeScript 5.9.3's lib .d.ts files, from its npm package fetched by sha256 in the fetch phase, and this repository's src and mods","over":["node_modules/typescript/lib after npm ci"],"because":"a pinned package keeps the corpus from moving with a dependency bump, and the build phase needs no npm ci, which would want the network; src and mods give real TSX and the repository's own code","binding":"none: this session owns no active work order"} +{"id":"d-87146256","kind":"decision","at":"2026-10-27T18:16:28.890Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"add grammars/tree-sitter-typescript/corpus/limits.txt, read by the comparison alone, for the regression the docs name (a comparison after an import type) and the forms both grammars still err on","over":["add those cases to coherence.patch's corpus"],"because":"the task forbids changing the patch, and an intended regression should show in a named case or be listed nowhere; the still-erring forms must then stay as stock reads them","binding":"none: this session owns no active work order"} +{"id":"d-81eefc56","kind":"decision","at":"2026-10-27T18:16:29.562Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"deny the build phase's network in CI with docker run --network none on node:22.18.0-trixie pinned by its index digest (glibc 2.41, gcc, git)","over":["unshare -rn on the runner"],"because":"ubuntu-latest (24.04) restricts unprivileged user namespaces through AppArmor, so unshare -rn is not reliable there, while docker is on every hosted runner; the same digest serves amd64 and arm64 and was run on both","binding":"none: this session owns no active work order"} +{"id":"d-9053b541","kind":"decision","at":"2026-10-27T18:16:30.252Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"the build phase checks the network itself, refusing to run where it can connect to any of six hosts by name or address, and checks every file in its inputs folder against inputs.sha256 and the clone's commit again","over":["trust the --network none in ci.yml and fetch.sh's own digest checks"],"because":"a sandbox flag dropped from CI or a fetch that skips its digest would otherwise pass unseen; this way both fail by running, not by reading the scripts","binding":"none: this session owns no active work order"} +{"id":"d-30523c18","kind":"decision","at":"2026-10-27T18:16:31.156Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"record the parsers' digests in grammars/tree-sitter-typescript/parsers.sha256, read by build-phase.sh and the unit test","over":["keep expected_* variables in build.sh"],"because":"CI runs build-phase.sh directly, and the unit test should read data, not a script's text","binding":"none: this session owns no active work order"} +{"id":"d-289a7d20","kind":"decision","at":"2026-10-27T18:16:31.723Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"keep both test titles verbatim and have the spec bullets say what the unit tests now hold and what CI holds","over":["retitle the tests to what they hold"],"because":"the owner asked to keep the titles, since spec bullets name tests by exact title; the titles now name more than the unit tests run (token spelling, fetch, verify), which the bullets and this report say plainly","binding":"none: this session owns no active work order"} +{"id":"d-84695255","kind":"decision","at":"2026-10-27T18:16:32.310Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"drop the refuted lines whose red came from assertions the comparison replaced (the & operator node, every anonymous token, @ as string_fragment, the download, fetch and verify text checks) and record new witnessed ones","over":["keep them"],"because":"a refuted line claims the bullet's detector went red on that break; those detectors are gone from the unit test, and the run store keeps their records","binding":"none: this session owns no active work order"} +{"id":"en-f7f06d2f","kind":"enactment","at":"2026-10-27T18:16:57.286Z","session":"a3f414dba641b7895","agent":"general-purpose","commit":"887abd8","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"refute src/plugins/the TypeScript parsers read what their release cannot, and src/plugins/the TypeScript parsers are the ones their build makes","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant both bullets --each, 2 pass batched and alone (.coherence/runs/a3f414dba641b7895.a6b398ed.jsonl)"},"2":{"result":"done","evidence":"staged the stock parsers for the first bullet and the v3 rename variant's typescript parser for the second, each a copy over plugins/typescript; git status showed only those wasm files"},"3":{"result":"done","evidence":"refute recorded red for each; the first on its own assertion (import type with type arguments: the tsx grammar parses it with no error), the second on its own (the bundled typescript parser is the one build.sh builds)"},"4":{"result":"done","evidence":"restored both wasm files from copies taken before the break; cmp equal and git status clean for plugins/"},"5":{"result":"done","evidence":"run --invariant both bullets --each again, 2 pass batched and alone"},"6":{"result":"skipped","because":"each red came from its break"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/a5eab130eb75915c1.95536bda.jsonl b/.coherence/journal/a5eab130eb75915c1.95536bda.jsonl new file mode 100644 index 00000000..b13e5f2e --- /dev/null +++ b/.coherence/journal/a5eab130eb75915c1.95536bda.jsonl @@ -0,0 +1,5 @@ +{"id":"d-dddffe34","kind":"decision","at":"2026-10-26T23:38:06.296Z","session":"a5eab130eb75915c1","agent":"general-purpose","commit":"c30c378","dirty":true,"chose":"read every TypeScript and JavaScript file through the TSX grammar alone (tree-sitter-tsx.wasm from tree-sitter-typescript 0.23.2)","over":["a parser per file pattern (TypeScript grammar for .ts, TSX for .tsx and JavaScript), a core change for treeSitter.parsers"],"because":"over 15,829 files of PostHog and Coherence the TSX grammar reads every .ts file the TypeScript grammar reads but two copies of one vendored file with an old-style row cast, while the TypeScript grammar errs on 3,196 of PostHog's 3,510 .tsx files; the core's readers take a text and no file name, so a parser per pattern would change their signature for two files","binding":"none: this session owns no active work order"} +{"id":"d-16ba447d","kind":"decision","at":"2026-10-26T23:38:12.438Z","session":"a5eab130eb75915c1","agent":"general-purpose","commit":"c30c378","dirty":true,"chose":"TypeScript's queries read no require() call and no dynamic import(), as the hand-written reader read none","over":["reading require(\"m\") and import(\"m\") as whole-module imports"],"because":"parity first: PostHog's frontend holds dynamic import() in 449 files (lazy scenes), and reading them would widen every closure and mass at once, a change of policy of its own to weigh apart from the move to a parser","binding":"none: this session owns no active work order"} +{"id":"d-8cf9c168","kind":"decision","at":"2026-10-26T23:38:12.701Z","session":"a5eab130eb75915c1","agent":"general-purpose","commit":"c30c378","dirty":true,"chose":"a default import is read as the name default (@import.default) and a default export by name, or the declaration that is the default, through @default; a capture whose name starts with an underscore is the queries' own, for a predicate","over":["keeping isDefaultExport and defaultNames as hand-written text readers in TypeScript's interfaces table"],"because":"a default import binds a name no node spells as default, and export { x as default } needs a predicate on the alias; leaving them hand-written would keep a second reader of TypeScript's text beside the parser, which the parser path exists to end","binding":"none: this session owns no active work order"} +{"id":"en-7b3494af","kind":"enactment","at":"2026-10-26T23:44:15.144Z","session":"a5eab130eb75915c1","agent":"general-purpose","commit":"c30c378","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"explicit","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run a5eab130eb75915c1.6b50c8c9 batched and --each, 3 green"},"2":{"result":"done","evidence":"dropped the @import.default pattern (typescript.scm); read every eject file as utf8 (eject.ts); diff read for each"},"3":{"result":"done","evidence":"refuted both; red on the test's own assertion (default <- react missing; its parser copied byte for byte); a third break, refusing _ captures, broke the CLI's own TypeScript reading, so refute recorded nothing and it does not count"},"4":{"result":"done","evidence":"cmp against copies taken before each break"},"5":{"result":"done","evidence":"run again batched and --each, 3 green, refutation witnessed"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} +{"id":"d-b4fe6dee","kind":"decision","at":"2026-10-26T23:55:12.593Z","session":"a5eab130eb75915c1","agent":"general-purpose","commit":"c30c378","dirty":true,"chose":"leave a file the TSX grammar cannot parse read by what its parse holds: 8 of PostHog's 15,507 TypeScript files parse to an ERROR root and lose every declaration, 19 lose those after a top-level ERROR (a 0.23.2 grammar bug with a property named in... after T[], and import('m').T in some type positions), and 10 local export renames (export { a as b }, no from) are no longer aliases","over":["duplicating every declaration pattern under (ERROR ...) for a root ERROR, and a core rule reading renames from export lists"],"because":"the loss is 0.2% of files and 10 renames in 15,507 files against hundreds of imports and declarations the hand-written readers misread; an ERROR-anchored copy of the queries matched only root ERRORs over PostHog but doubles typescript.scm, and export-list renames would need a capture and an answers-agree rule of their own: follow-ups to weigh apart","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/a72441caddecdcdf9.2f5da31a.jsonl b/.coherence/journal/a72441caddecdcdf9.2f5da31a.jsonl new file mode 100644 index 00000000..8557a052 --- /dev/null +++ b/.coherence/journal/a72441caddecdcdf9.2f5da31a.jsonl @@ -0,0 +1,9 @@ +{"id":"d-9aee2748","kind":"decision","at":"2026-10-27T17:56:56.326Z","session":"a72441caddecdcdf9","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"Retire the local cutting path entirely: src/lifecycle/prerelease.ts keeps only the checks (prereleaseProblems), its entry takes no arguments, refuses the old --notes and --dry-run with a pointer to the workflow, and runs no gh, npm or clone","over":["Keep the local script as --dry-run only"],"because":"A local dry-run answers for the local view (working tree, local remotes and refs), the very view that review after review found diverging from what would ship; the authoritative answer is the workflow's own run over a clean checkout, and keeping a second path would mean holding two views in step by hand","binding":"none: this session owns no active work order"} +{"id":"d-22e7eadc","kind":"decision","at":"2026-10-27T17:56:56.598Z","session":"a72441caddecdcdf9","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"Drop the working-tree checks (tracked changes, files the package names that no commit holds) and prereleaseCommands from prerelease.ts, and their refuted: lines","over":["Keep the working-tree checks as belt and braces in CI"],"because":"The workflow checks the branch out clean, so those checks guard a state the workflow cannot reach; the bullet now claims the clean checkout by construction, and a check that can never fire there would overstate what the tests hold","binding":"none: this session owns no active work order"} +{"id":"d-fd2e2beb","kind":"decision","at":"2026-10-27T17:56:56.860Z","session":"a72441caddecdcdf9","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"Take the notes as a string input, passed to the shell through the step's environment and written to a file for --notes-file","over":["Take the notes as a path in the repository at the ref"],"because":"A path would require committing the notes to the branch being released, changing the very commit cut or adding one after the version bump; a string through env is never spliced into a script, and the shape test holds that no run holds an expression","binding":"none: this session owns no active work order"} +{"id":"d-53ec1885","kind":"decision","at":"2026-10-27T17:56:57.120Z","session":"a72441caddecdcdf9","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"Check out refs/heads/ with fetch-depth: 0 and persist-credentials: false, resolve the sha once with git rev-parse HEAD as a step output, and target the release at that sha","over":["Check out the bare ref input and target github.sha or the branch name"],"because":"The fully qualified ref makes the checkout itself refuse a tag or a commit; github.sha is the commit of the workflow's own ref (main when dispatched from main), not the branch cut, and a branch name may move while the run goes","binding":"none: this session owns no active work order"} +{"id":"d-ca07421e","kind":"decision","at":"2026-10-27T17:56:57.379Z","session":"a72441caddecdcdf9","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"One job with contents: write at job level (contents: read at workflow level), the token given only to the release step's env, no environment","over":["Two jobs (pack with read, release with write via an uploaded artifact), or the Release environment"],"because":"It mirrors release.yml's publish job; with persist-credentials: false and npm ci --ignore-scripts the token reaches no other step; a second job adds two more pinned actions and an artifact hop for little; the Release environment is npm's and its branch policy is for main","binding":"none: this session owns no active work order"} +{"id":"d-d17f55f6","kind":"decision","at":"2026-10-27T17:56:57.639Z","session":"a72441caddecdcdf9","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"Hold the workflow's shape with a strict block-YAML reader inside prerelease.test.ts that throws on any form it does not take","over":["Add a YAML library as a dependency, or match the workflow text with regular expressions as ci.test.ts does"],"because":"The package keeps very few dependencies; a regex over text cannot say where a key stands, while a parse can hold on, permissions, steps and env by position; a reader that refuses what it does not know cannot misread (Ruby's YAML parse of the file agreed with it)","binding":"none: this session owns no active work order"} +{"id":"d-8c0f5af6","kind":"decision","at":"2026-10-27T17:56:57.908Z","session":"a72441caddecdcdf9","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"Skip actionlint and say so","over":["Download an actionlint binary for this check"],"because":"No pinned actionlint binary exists in the repository or on this machine, and npx actionlint is not a thing; fetching an unpinned binary would be an unchecked download","binding":"none: this session owns no active work order"} +{"id":"d-e799005a","kind":"decision","at":"2026-10-27T17:56:58.176Z","session":"a72441caddecdcdf9","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"Mirror release.yml's tarball smoke check (install the tarball into an empty project and run spec --check) before creating the prerelease, on node 22.18 as ci.yml runs the TypeScript sources","over":["Attach the tarball unchecked, as the local script did"],"because":"A prerelease carries the tarball adopters install; the same check release.yml runs before npm publish costs a minute and catches a tarball that does not run","binding":"none: this session owns no active work order"} +{"id":"en-74a8b6d2","kind":"enactment","at":"2026-10-27T17:57:06.746Z","session":"a72441caddecdcdf9","agent":"general-purpose","commit":"887abd8","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"refute src/lifecycle/a prerelease carries main","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant 'a prerelease carries main' --each, pass batched and alone"},"2":{"result":"done","evidence":"seven single-site breaks (six in prerelease.yml, one in prerelease.ts), each diff read before the run"},"3":{"result":"done","evidence":"refute recorded red seven times; the test file run alone showed each red on its own assertion"},"4":{"result":"done","evidence":"each file restored from a copy taken before the break, cmp identical"},"5":{"result":"done","evidence":"run --invariant 'a prerelease carries main' --each after the last restore, pass batched and alone"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/a81173c1d817c26f3.3450b7b9.jsonl b/.coherence/journal/a81173c1d817c26f3.3450b7b9.jsonl new file mode 100644 index 00000000..5391aa4d --- /dev/null +++ b/.coherence/journal/a81173c1d817c26f3.3450b7b9.jsonl @@ -0,0 +1 @@ +{"id":"d-18923d9c","kind":"decision","at":"2026-10-27T21:14:45.215Z","session":"a81173c1d817c26f3","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"compare.mjs fails on any region of difference in a corpus case no intended-differences.json entry names, in every corpus alike (upstream's, Coherence's, limits.txt), whatever an entry's query overlaps, naming the case and the entries whose query overlapped; an entry's query alone still allows a region in a --files input (TypeScript's lib, src, mods)","over":["special-casing limits.txt by its file name, or holding --files inputs to the same rule, which would fail the build whenever Coherence's own source gains a form the patch fixes"],"because":"limits.txt promised its forms stay as the stock grammar reads them, but only entry-named cases were held to one region: the blind reviewer's in-paren variant turned 'a method named in after another member' into an improvement and member-named-in's query let it pass; inputs from --cases are cases by construction (isCase), so one rule covers every corpus and only the regression's own named case may differ in limits.txt","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/a8c20833df2abb361.a46f7968.jsonl b/.coherence/journal/a8c20833df2abb361.a46f7968.jsonl new file mode 100644 index 00000000..5f720c6e --- /dev/null +++ b/.coherence/journal/a8c20833df2abb361.a46f7968.jsonl @@ -0,0 +1,2 @@ +{"id":"en-82833b4c","kind":"enactment","at":"2026-10-25T02:12:45.982Z","session":"a8c20833df2abb361","agent":"general-purpose","commit":"b91e4ad","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant for both bullets with --each, ef76c476 runs shard: batched 2 pass, alone 2 pass (after two earlier attempts there recorded not run and fail alone because Node 25 prints the spec reporter and the config's testMatch reads TAP; rerun through a node shim that adds --test-reporter=tap when none is named)"},"2":{"result":"done","evidence":"one-line breaks, each an exact single replacement asserted present: the wasm impl's exports set false in foreignExports (plugins/rust/rust-entrances.ts), and the lists slot dropped from readLiteral (src/lifecycle/mirrors.ts); git diff --no-index against the copy showed only that line"},"3":{"result":"done","evidence":"two refute records in the ef76c476 runs shard, each red on its own test"},"4":{"result":"done","evidence":"each file restored from a copy taken before its break, cmp clean"},"5":{"result":"done","evidence":"run --invariant for both bullets with --each after restoring: batched 2 pass, alone 2 pass, refutation witnessed"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} +{"id":"d-bd0638ec","kind":"decision","at":"2026-10-25T02:12:46.213Z","session":"a8c20833df2abb361","agent":"general-purpose","commit":"b91e4ad","dirty":true,"chose":"an exported impl's methods, #[wasm_bindgen(start)] and UniFFI exports are read under the Rust plugin's existing foreign export rule, named Type::method, and an example's main under a new example rule","over":["a wasm export, a uniffi export and a C-ABI export rule of their own (the shape Holofield's ejected copy used) | an example read as a binary"],"because":"upstream's foreign export rule already says what each of these is, a function code outside Rust calls by its name, and splitting it would rename the rule every adopter's coverage already counts; an example is run by cargo run --example, not installed as a binary, so naming it a binary would propose binary names for files Cargo never builds as one. Checked on Holofield: the branch detects the same 153 (file, symbol) pairs as its ejected plugin, against 34 on main","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/a8c6256d564d40a3c.791d40d1.jsonl b/.coherence/journal/a8c6256d564d40a3c.791d40d1.jsonl new file mode 100644 index 00000000..baca64e3 --- /dev/null +++ b/.coherence/journal/a8c6256d564d40a3c.791d40d1.jsonl @@ -0,0 +1,11 @@ +{"id":"en-24fa2065","kind":"enactment","at":"2026-10-27T19:30:50.610Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant (the three bullets) --each passed batched and alone before the breaks, .coherence/runs/a8c6256d564d40a3c.e09e8193.jsonl"},"2":{"result":"done","evidence":"staged four breaks, each one edit read in git diff: noeq parsers (built from coherence.patch with = dropped from member_follows) over plugins/typescript/*.wasm; the ls-remote failure read as no tag in prereleaseProblems; contents: write on the workflow's build job"},"3":{"result":"done","evidence":"refute recorded red for src/plugins/the TypeScript parsers read what their release cannot (class field named in: the tsx grammar parses it with no error), src/plugins/the TypeScript parsers are the ones their build makes (the bundled typescript parser is the one build.sh builds), and src/lifecycle/a prerelease carries main twice (origin's tags could not be listed; build:, which may write, is the job that releases), each on its own assertion"},"4":{"result":"done","evidence":"each restored from a copy taken before the break, cmp clean, plugins/ clean against HEAD"},"5":{"result":"done","evidence":"run --invariant (the three bullets) --each passed batched and alone after restoring"},"6":{"result":"skipped","because":"every red came from its break, read from the failing assertion"}},"binding":"none: this session owns no active work order"} +{"id":"d-4379319b","kind":"decision","at":"2026-10-27T19:31:11.518Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"build-phase.sh reads upstream's corpus from the pinned upstream tree, extracted once and made read-only; Coherence's own expected trees move out of coherence.patch into grammars/tree-sitter-typescript/corpus/; the patched grammar is the clean tree with common/define-grammar.js and common/scanner.h alone copied from an applied copy, and a patch whose applied tree differs from upstream's in any other path, or turns either file into anything but a regular file (git diff-tree --raw of the two trees), is refused by name","over":["parsing coherence.patch's diff headers for the paths it touches, or keeping the corpus inside the patch and checking it separately"],"because":"a check must never trust input the checked thing controls (d-a5c35add): comparing the trees git produces cannot be fooled by header tricks (renames, mode lines, traditional diffs), and copying only the two files makes a change elsewhere unable to reach the build even if the refusal had a gap","binding":"none: this session owns no active work order"} +{"id":"d-60bc2d0f","kind":"decision","at":"2026-10-27T19:31:11.764Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"compare.mjs holds the patched parsers to every expected tree any corpus case declares (upstream's and Coherence's), printed as tree-sitter test prints it, fields only where the case shows them, and holds each intended difference to its cases one form to a case: each named case must hold exactly one region of difference per dialect, and that region must be the entry's; an improvement's case must declare an expected tree","over":["keeping the per-case rule and relying on tree-sitter test alone for expected trees"],"because":"the shipped wasm, not only the native test build, is then held to the fixed reading, so a structure change inside an improvement's region (the reviewer's character reference break) fails, and a form broken back to the stock reading fails in its own case (the class field named in) instead of hiding behind another form in the same case","binding":"none: this session owns no active work order"} +{"id":"d-674502f0","kind":"decision","at":"2026-10-27T19:31:12.024Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"member-named-in's query captures the names of properties, class fields, methods, method signatures and abstract method signatures matching ^in(stanceof)?([0-9_$\\\\]|$), and a separate entry, statement-beginning-with-in, captures identifiers matching the same, each with one-form corpus cases","over":["^in over properties and fields alone, or a class of every non-letter after in"],"because":"those are exactly the names the scanner change acts on (a digit, _, $ or \\ after in or instanceof, or in and instanceof themselves); index, input, init and inü read alike in both parsers and are no longer captured, methods and statements beginning so are fixed by the patch and would fail CI as unlisted improvements, and a rarer non-ASCII non-letter after in fails closed","binding":"none: this session owns no active work order"} +{"id":"d-b49c9505","kind":"decision","at":"2026-10-27T19:31:12.286Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"build-phase.sh reads the upstream clone with git --no-replace-objects and refuses the extracted files unless they hash, in a repository of the build's own, to the tree inputs.sh pins (upstream_tree)","over":["rev-parse HEAD, which git replace leaves at the pinned commit while changing what archive reads"],"because":"a replace object on scanner.h's blob left rev-parse HEAD unchanged; with --no-replace-objects the real blob is read, and with it dropped the tree hash refuses the build, so the content, not a ref, is what is checked","binding":"none: this session owns no active work order"} +{"id":"d-ccf108f5","kind":"decision","at":"2026-10-27T19:31:12.542Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"the build phase's network check is described as a tripwire everywhere; the denial is sandbox-exec on macOS and docker --network none on Linux and in CI; build.sh on Linux runs the phase in docker when docker is present and falls back to unshare -rn saying it leaves filesystem unix sockets reachable; the image digest lives once in inputs.sh, which CI sources","over":["keeping unshare -rn as the Linux path and the CI image spelled twice"],"because":"a stubbed net module passes the check, so calling it the denial over-claimed; unshare -rn takes the network namespace but not unix sockets on disk such as a docker daemon's; one pinned image for both runners keeps them the same build","binding":"none: this session owns no active work order"} +{"id":"d-07c41d9b","kind":"decision","at":"2026-10-27T19:31:25.721Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"the prerelease workflow test is a lint of the file's shape alone (top-level keys, dispatch only, each job's permissions with one job allowed contents: write, that job releasing and checking nothing out, no id-token, write-all or environment, every uses pinned by commit), line-based and refusing YAML forms it does not read; the hand-written YAML reader is dropped, and the spec bullet says the workflow's behaviour is held by how it is built and by its runs","over":["keeping the YAML reader and its order, injection and publish checks, or adding actionlint to CI"],"because":"no YAML parser is available without a new dependency, the reviewer beat the text checks five ways, and a text check cannot show what a workflow does; actionlint 1.7.7 run locally in docker passes both workflows, and adding it to CI is left for a pinned-binary change of its own","binding":"none: this session owns no active work order"} +{"id":"d-926cf854","kind":"decision","at":"2026-10-27T19:31:25.979Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"prerelease.yml splits into a build job with contents: read (check, npm ci, pack, smoke, upload-artifact) and a release job with contents: write that checks nothing out, downloads the tarball, creates the tag at the build job's sha through the refs API, which fails if the tag exists, and runs gh release create --verify-tag on it","over":["one job holding contents: write while it runs the branch's code, and gh release create --target, which uses a tag that already exists wherever it points"],"because":"least privilege for the job that executes untrusted code, and a release that cannot land on a tag at another commit: creating the ref fails closed instead of a check that could pass stale","binding":"none: this session owns no active work order"} +{"id":"d-bbbfe899","kind":"decision","at":"2026-10-27T19:31:26.235Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"the prerelease smoke check installs the tarball in an empty folder and runs coherence plugin check typescript and plugin check python from it","over":["spec --check in an empty folder, or a digest check of the tarball's wasm"],"because":"each plugin check reads its fixtures through the bundled parser and exits 1 on a failure: a tarball with plugins/ and dist/bundled removed, or with the parsers removed, fails both, where spec --check passed it","binding":"none: this session owns no active work order"} +{"id":"d-8272e611","kind":"decision","at":"2026-10-27T19:31:26.486Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"prereleaseProblems treats a failed git ls-remote of the remote's tags as a reason (the tags could not be listed), never as no such tag","over":["reading empty output as no tag whatever the exit status"],"because":"fail closed: an unreachable remote said nothing of the tag, and the refutation that restored the old reading went red on the new assertion","binding":"none: this session owns no active work order"} +{"id":"d-0c5c412c","kind":"decision","at":"2026-10-27T19:31:26.738Z","session":"a8c6256d564d40a3c","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"keep the prerelease concurrency group global with cancel-in-progress: false, and document that GitHub keeps one pending run, so a third dispatch cancels the pending second before it checks anything out","over":["a group per ref, which lets two branches race to one version's tag, or cancel-in-progress: true, which could stop a cut between its tag and its release"],"because":"serializing every cut keeps the free-tag check and the release in one critical section, a cancelled pending run has done nothing and shows as cancelled to be dispatched again, and the release job's ref creation still fails closed if a tag appears anyway","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/a9989dca94e0c7e7a.af059e78.jsonl b/.coherence/journal/a9989dca94e0c7e7a.af059e78.jsonl new file mode 100644 index 00000000..826797da --- /dev/null +++ b/.coherence/journal/a9989dca94e0c7e7a.af059e78.jsonl @@ -0,0 +1,13 @@ +{"id":"d-540ad200","kind":"decision","at":"2026-10-27T21:27:01.852Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"the defect verb refuses a record that says nothing of where it lies: it takes --file, --component, or --unplaced \"\", and the refusal names each and lists the components","over":["a warning on a defect written with no file, which the agent can miss","placing older records by their prose"],"because":"20 defects in this repository's journal named no file and counted toward no subsystem; asking at the write leaves that accident no way to happen (d-9d919dd8), and --unplaced keeps the honest case of a fault no file holds; older records keep their derivation, since nothing but their prose would place them","binding":"none: this session owns no active work order"} +{"id":"d-d0dad6f0","kind":"decision","at":"2026-10-27T21:27:02.113Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"every verb that answers or cites an earlier record (retract, resolved, classify, dismiss, experiment close, acknowledge, --cite) resolves ids in the journal of every worktree, the journals the dead-end reading reads","over":["resolving only the escalate and acknowledge ids the remedy prints","printing the worktree's path in the remedy so the agent changes folder"],"because":"the reading names ids from any worktree, so any id it prints must work from the checkout it speaks in; one rule for every answering verb keeps classify, which the reading also prints, from failing the same way","binding":"none: this session owns no active work order"} +{"id":"d-2346ed56","kind":"decision","at":"2026-10-27T21:27:02.641Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"a retracted defect is no defect to any reader: defectStates leaves it out, so no floor, convergence count or dead end reads it","over":["leaving it out of the dead-end count alone"],"because":"a withdrawn report is no fault, and the floor and the convergence reading counting it would disagree with the alarm","binding":"none: this session owns no active work order"} +{"id":"d-8f125f71","kind":"decision","at":"2026-10-27T21:27:16.661Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"loadJournal and loadJournalAcrossWorktrees report a store file they cannot read as damaged on every path, the checkout's own included, and never throw","over":["catching the error in readDeadEnds alone"],"because":"orient also reached loadJournal through the escalation block and the lexicon reading, so a guard at one caller left the crash on the others; a damaged file said is what the Journal spec's bullet states","binding":"none: this session owns no active work order"} +{"id":"d-7fb02821","kind":"decision","at":"2026-10-27T21:27:16.933Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"keep a derived index of the other worktrees' journals in the user's cache (userCacheDir()/journal-index, one per repository): each store file by its identity (device, inode, size, modification and change time) and the sha256 of its bytes, each digest's lines, each line's parse; a file whose identity matches is not read, files equal by digest are parsed once, and only what the current files name is kept","over":["reading only the record kinds the dead-end reading needs, which still reads every byte","filing by size and modification time alone, which a rewrite can set back"],"because":"orient and spec --check read 11,000 store files, 143 MB, on every start for 1,700 distinct records; the files stay the truth, a change time cannot be set back, and a missing, malformed or foreign index answers nothing so the reading falls back to reading every file","binding":"none: this session owns no active work order"} +{"id":"d-dcf35550","kind":"decision","at":"2026-10-27T21:27:17.200Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"placement is its files, else its guard: a defect's guard adds its component only when the defect names no file below the root, and the root only when nothing deeper is named; every path, at the write and in the reading, is normalized with projectFile in the spec model before its owner is decided","over":["the union of files and guard the code had","normalizing in the defect verb alone"],"because":"a guard closes a defect from wherever its invariant is declared, so adding its component counted the defect toward a subsystem that holds no fault, a false alarm; one normalizer both sites call keeps gadget/../widget/knob.ts from being gadget's at the write or in the reading","binding":"none: this session owns no active work order"} +{"id":"d-1a3b2149","kind":"decision","at":"2026-10-27T21:27:17.469Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"orient says nothing of the dead-end reading when no subsystem is at a dead end; spec --check and the convergence reading keep the line of what was read and the unclassified defects","over":["a shorter orient line naming the unclassified defects"],"because":"src/lifecycle/no totals are injected forbids a total in a hook injection, and the line was a count on every start; at a dead end orient keeps the counts the alarm rests on (supersedes d-5d94248c for orient)","binding":"none: this session owns no active work order"} +{"id":"d-71c03a92","kind":"decision","at":"2026-10-27T21:27:17.746Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"the dead-end header and the Spec bullet say the alarm serves an agent that wants to work helpfully and guards its accidents, not that nothing it counts is what the agents choose to report","over":["keeping the claim and adding defenses for it"],"because":"the owner's direction d-9d919dd8: the car need not be uncrashable; a retraction, a class and a component are the agent's to choose","binding":"none: this session owns no active work order"} +{"id":"d-d2d20380","kind":"decision","at":"2026-10-27T21:27:18.021Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"a duty newer than a plugin's interface says what of that version it asks (DUTY_SINCE carries since and asks), not the first clause of the version's change text","over":["quoting a longer slice of PLUGIN_API_CHANGES"],"because":"the reference reading's reason quoted pluginApi 3's parser-path change, which the duty does not ask; each duty names its own need: the reference map, topLevelSymbols","binding":"none: this session owns no active work order"} +{"id":"en-cc75670d","kind":"enactment","at":"2026-10-27T21:45:58.430Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant (6 bullets) --each before the breaks: 6 pass batched, 6 pass alone, recorded in .coherence/runs/a9989dca94e0c7e7a.636da992.jsonl"},"2":{"result":"done","evidence":"11 one-line breaks of behavior (placement requirement, path normalization, guard union, worktree prefix, answering lookup, own-file throw, index identity, retracted defect, orient line x3 bullets, duty reason); each diff read before refuting"},"3":{"result":"done","evidence":"refute recorded red for each of the 11 in .coherence/runs/a9989dca94e0c7e7a.636da992.jsonl; a direct run of the via test showed each red on its own assertion (e.g. 'a retracted defect counts toward no dead end', 'a file whose identity changed is read again')"},"4":{"result":"done","evidence":"each file restored from a copy taken before the break, cmp clean every time (the code is uncommitted)"},"5":{"result":"done","evidence":"run --invariant (6 bullets) --each after: 6 pass batched, 6 pass alone; every totality oracle that passed batched passes alone"},"6":{"result":"skipped","because":"every red came from its break: each failing assertion named the behavior broken"}},"binding":"none: this session owns no active work order"} +{"id":"u-561ee937","kind":"unable","at":"2026-10-27T21:46:16.473Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"what":"make the whole orient read on past an unreadable store file in the checkout's own journal","because":"loadJournal still throws there, on purpose: lexicon apply and the answering verbs refuse a write while a file that may hold their answer cannot be read (lexicon-work.test.ts), and orient reaches loadJournal through the escalation block and the lexicon reading before the spec block; the reading path (loadJournalAcrossWorktrees, readDeadEnds, spec --check, orient's spec block) reports it as damaged; a read-only loader for orient's other blocks is the next step","cites":["d-8f125f71"],"binding":"none: this session owns no active work order"} +{"id":"d-ab8fbd69","kind":"decision","at":"2026-10-27T21:46:17.717Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"chose":"accept the index's costs: the first reading after the index is lost or most files changed reads every file and writes the index (about 2 s over 116 worktrees), each answering verb now pays an across-worktree reading (about 0.1 s with the index), and resident memory of the cost probe stays about where it was (365 MB peak against 340 MB; one bare reading adds 53 MB against 70 MB before)","over":["a resident daemon holding the parsed journals","reading only the record kinds the dead-end reading needs"],"because":"the time every orient and spec --check pays falls from about 300 ms to about 105 ms on a warm file cache and from about 1.4 s cold, and nothing the reading sees changes (the original and new readers return identical records, damage and worktrees on this repository's 111 worktrees); the probe's peak memory is the parsers and the spec model, not the journal","cites":["d-7fb02821"],"binding":"none: this session owns no active work order"} +{"id":"c-7e051032","kind":"conjecture","at":"2026-10-27T21:48:53.834Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","commit":"766fba1","dirty":true,"observation":"src/adapters/rust.test.ts 'a Rust refutation stages an overlay pair...' failed once in a full npm test (the reference set came back empty where write_class at src/kernel/mod.rs:5 was expected) and passed in two other full runs and alone","couldBe":["the instrument is wrong","rust-analyzer had not finished indexing when the test asked for references under a loaded machine","an earlier test in the run left state the Rust test reads"],"discriminatedBy":"run src/adapters/rust.test.ts 20 times alone and 5 times in the full suite under load, and see whether the empty reference set follows load or test order","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/aa78b6ceaeb4845e0.a577812c.jsonl b/.coherence/journal/aa78b6ceaeb4845e0.a577812c.jsonl new file mode 100644 index 00000000..2e42b214 --- /dev/null +++ b/.coherence/journal/aa78b6ceaeb4845e0.a577812c.jsonl @@ -0,0 +1,21 @@ +{"id":"d-b95d2eb5","kind":"decision","at":"2026-10-27T17:49:14.038Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"a dead end's subsystem is the component holding each file a defect names plus the component its close's guard names, the root component only when no deeper one is named; a defect naming neither is placed nowhere","over":["grouping by file, which splits one design across its modules and misses the 23 parse-store defects that name no file","inferring the subsystem from a defect's prose"],"because":"the component is the unit Coherence already holds specs, guards and ownership by; this session's parse-store defects name src/plugins by file or by guard, and placing the rest by their words would be a guess the reading cannot show","binding":"none: this session owns no active work order"} +{"id":"d-9ddcfea6","kind":"decision","at":"2026-10-27T17:49:14.308Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"a round is the commit HEAD named when a defect was written","over":["calendar days","a new round at each guarded close"],"because":"each blind-review round's fixes landed as a commit before the next round's findings, so a round's findings share a commit (this session: 870296d through 887abd8, 9 rounds); a session spans days unevenly, and the closes were written seconds after each defect, so a close boundary made every defect its own round","binding":"none: this session owns no active work order"} +{"id":"d-23d90bee","kind":"decision","at":"2026-10-27T17:49:14.574Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"a dead end also requires defects that came back through a guard the subsystem already had: a defect whose close names a guard that had closed an earlier defect there before it was written","over":["defects, classes and rounds alone","a defect whose class or family the subsystem had already guarded"],"because":"on this journal's history src/lifecycle reached 13 defects, 6 classes and 6 rounds between 2026-10-08 and 2026-10-22 with each defect buying a new guard of its own, which is converging work; counting a repeat by class instead counted the hand-list sweep of src/readings/scope as 5 returns; returns through an earlier guard were 0 for every other component in every 14-day window and 3 for src/plugins by its second review round","binding":"none: this session owns no active work order"} +{"id":"d-673c5a2e","kind":"decision","at":"2026-10-27T17:49:14.844Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"thresholds: 8 defects, 3 classes or families, 3 rounds and 3 returns since the subsystem's first witnessed guard, within the 14 days the convergence reading also uses","over":["a lower bar of 2 returns","a count over all time"],"because":"src/plugins crossed all four at the 04:00 round on 2026-10-27, before the third and fourth blind reviews, and holds 26, 7, 11 and 12 now; the nearest other component, src/lifecycle, holds 5, 2, 3 and 1, so 3 returns leaves a margin over its 1; all time would keep a subsystem flagged after it stopped failing","binding":"none: this session owns no active work order"} +{"id":"d-e6d763a3","kind":"decision","at":"2026-10-27T17:49:15.109Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"a dead end is a derived reading that asks the agent to escalate, and a human's acknowledgement of an escalation citing one of its defects restarts its count","over":["Coherence writing an escalation record itself when the reading trips"],"because":"every record carries the session and agent that wrote it, and a reading is derived and never stored as truth (Coherence.spec.md trust levels); an escalation written by a reading would be attributed to no one and written again at every start; the agent's escalation, once written, heads every read until a human acknowledges it, which is the existing way to ask a human","binding":"none: this session owns no active work order"} +{"id":"d-eabb7952","kind":"decision","at":"2026-10-27T17:49:15.380Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"dead ends ride on the defect floor the spec model computes once, advisory and never a spec problem, read by spec --check, orient and the convergence reading","over":["a spec problem that refuses a stop","a separate computation in each reader"],"because":"the floor's guard failures are advisory for the same reason: a dead end cannot be repaired by the session that sees it within the session, and refusing its stop would refuse it for a record nobody can unwrite; one computation keeps the three readings from disagreeing, as repeats already do","binding":"none: this session owns no active work order"} +{"id":"d-9ada9470","kind":"decision","at":"2026-10-27T17:49:15.656Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"families count toward a dead end's classes as classes do","over":["leaving families out as guard-failure counting does"],"because":"a family exempts a defect from guard failure because no one guard covers it, but a dead end is about the subsystem's design failing in many shapes; the owner's brief said a dead end spans classes and families alike","binding":"none: this session owns no active work order"} +{"id":"rt-745246f5","kind":"retraction","at":"2026-10-27T17:56:18.171Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"of":"d-b95d2eb5","because":"the owner asked that a defect name its component at the write, so the reading queries the record and derives only for records without it; d-b95d2eb5's derivation now applies to those alone","binding":"none: this session owns no active work order"} +{"id":"rt-8c4404d4","kind":"retraction","at":"2026-10-27T17:56:18.487Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"of":"d-eabb7952","because":"the dead-end reading now reads every worktree's journal, which the spec model, loaded on every hook, should not pay for; the reading is computed by spec --check, orient and the convergence reading from one function instead","binding":"none: this session owns no active work order"} +{"id":"d-777c1614","kind":"decision","at":"2026-10-27T17:56:18.773Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"a defect record carries its component, settled at the write: --component when given (refused unless it names a folder holding a spec), else the one component whose folder holds every file it names; files in several components, or none, write no component and the verb says how to name one","over":["a list of components per defect","refusing a defect whose files span components"],"because":"the alarm queries one field rather than inferring; a defect is one finding about one part of the design, and refusing a write for its placement would lose the finding; the store is append-only, so older records keep no field and a reader places them by d-b95d2eb5's derivation (files, else the guard's component) and counts how many it derived or could not place","binding":"none: this session owns no active work order"} +{"id":"d-b66c7fec","kind":"decision","at":"2026-10-27T17:56:19.051Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"the journal loader reads every worktree git lists for the repository (loadJournalAcrossWorktrees in store.ts), each record once by id, skipping another worktree's store file whose name and size it already read, read only; the dead-end reading uses it, the defect floor and the other readings keep their own checkout until asked","over":["a private worktree walk inside the alarm","moving every journal reading across worktrees now"],"because":"an agent records defects in the checkout it works in, so one checkout's journal missed them; a committed shard is sealed, so name and size identify its records and 106 worktrees read in about 120 ms here against 13 ms for one; the floor is computed by the spec model on every hook, which should not pay that cost unasked (d-23d90bee's thresholds were measured on this checkout's journal and hold across all 106)","binding":"none: this session owns no active work order"} +{"id":"d-6beb305a","kind":"decision","at":"2026-10-27T17:56:19.359Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"the dead-end reading is one function, readDeadEnds, that spec --check, orient's spec block and the convergence reading each call; it stays advisory and never a spec problem","over":["a field on the spec model's defect floor","a spec problem that refuses a stop"],"because":"the spec model loads on every hook and should not read 100 worktrees each time; one function keeps the three readings from disagreeing; advisory because a dead end cannot be repaired inside the session that sees it, as guard failures are advisory","binding":"none: this session owns no active work order"} +{"id":"d-29f52b0c","kind":"decision","at":"2026-10-27T17:56:19.641Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"the reading names how many worktrees it read and, most first, the five that held records no other did, with the rest counted and named whole in query convergence --json","over":["naming every worktree read"],"because":"this repository lists 106 worktrees; a line naming each would bury the dead end it reports, while the worktrees that hold records nowhere else are where a stuck agent's defects would be","binding":"none: this session owns no active work order"} +{"id":"d-d5bea2db","kind":"decision","at":"2026-10-27T17:57:10.004Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"lexicon apply lp-163c66d74f57ab90c25f0453 {\"change\":{\"action\":\"define\",\"name\":\"defect\",\"entry\":{\"properties\":{\"component\":\"The component a defect belongs to, as its folder: given with --component, or settled when the defect is written as the one component whose folder holds every file it names. A record written before the field, or whose files lie in several components, carries none; the dead-end reading then places it by its files, else by its guard's component, and says how many it placed that way and how many it could not.\",\"dead end\":\"A component that keeps collecting defects after its first guard, across classes and families, over several rounds (the commits they were recorded at), with defects coming back through guards it already had, within the convergence window: its guards are narrowing doors in a design that is wrong. spec --check, orient and the convergence reading name it with its defects, classes, rounds and window, read from every worktree's journal; the remedy is to stop adding guards there, review its representation, record the choice as a decision, and escalate it to a human, whose acknowledgement restarts the count.\",\"convergence\":\"The reading of whether discoveries repay, over a window: defects arriving by origin and catch, escapes per release, the share closed with a guard, repeats per class, dead ends, bullets over time, hotspot churn, and hook latency per Coherence version (query convergence).\"}},\"because\":\"the dead-end reading and the defect record's component field are new properties of defect; convergence now reports dead ends\"},\"human\":null}","over":["a concept of its own for dead end, apart from defect"],"because":"the owner asked for an alarm for agentic dead ends and for a defect to name its component; both are properties of defect, beside guard failure, and convergence now reports dead ends","cites":["d-6beb305a","d-777c1614"],"binding":"none: this session owns no active work order"} +{"id":"d-b66f940f","kind":"decision","at":"2026-10-27T17:57:14.264Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"lexicon apply lp-2b3704fa1299b7e947ef4946 {\"change\":{\"action\":\"define\",\"name\":\"orient\",\"entry\":{\"definition\":\"The start-of-cycle reading. Before acting, the session sees where the project stands and what heading follows from it. It shows escalations awaiting a human, structural defects, dead ends and guard failures, requirements stuck short of invariant, unreached mass, the session's own work order, and what peers recorded. One heading, derived from state; it also names the spec gaps beyond the adoption baseline.\"},\"because\":\"orient now names dead ends beside guard failures\"},\"human\":null}","over":["leaving orient's definition as it was"],"because":"orient's spec block now names dead ends beside guard failures, so the concept that lists what orient shows names them too","binding":"none: this session owns no active work order"} +{"id":"d-0f7f9434","kind":"decision","at":"2026-10-27T17:58:03.239Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"amend src/journal/close a defect: step 3 now says that when the dead-end reading names the defect's component, a different design for it is weighed first, not a narrower door in the same one, and the choice is recorded as a decision; a pitfall cites src/plugins' parse store","over":["a separate new step, which would renumber the steps every enactment recorded"],"because":"the parse store's four rounds each closed defects with a check at the site, as step 3 allowed, and the next round faulted those checks; the step that chooses the fix is where a dead end must change the choice","cites":["en-a4aad046"],"binding":"none: this session owns no active work order"} +{"id":"en-62da35fa","kind":"enactment","at":"2026-10-27T18:04:57.565Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant for the two dead-end bullets --each: pass batched and alone, before the breaks (.coherence/runs/aa78b6ceaeb4845e0.13558d9b.jsonl)"},"2":{"result":"done","evidence":"four breaks of behavior, one line each, diffed against a copy: first guard taken as the latest close; returns threshold dropped; --component refusal made unreachable; the worktree loop sliced to none"},"3":{"result":"done","evidence":"refute run for each of the four bullets; each test was first run alone with the break and failed on its own assertion (no DEAD END line; deadEnds not empty; exit 0 for 1; the other worktree's record not read)"},"4":{"result":"done","evidence":"each file restored from the copy taken before its break; cmp silent for dead-ends.ts (twice), verbs.ts and store.ts"},"5":{"result":"done","evidence":"run --invariant for all four bullets --each: 4 pass batched, 4 pass alone, refutation witnessed"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} +{"id":"en-6ca296c7","kind":"enactment","at":"2026-10-27T18:04:58.172Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"practice":"src/lifecycle/carry a lexicon change through","version":"f28a1b08","trigger":"command lexicon apply","steps":[{"text":"write the first sentence as the definition a session needs at a glance; the lexicon has no token ceiling; the start injection presents at most 2,000 tokens of it and decays the least recently named concepts to fit (d-2b4c96a2, d-f0da2f1f)"},{"text":"mark a concept \"protected\": true only when a human asks for it to stay whole however long the journal goes without naming it"},{"text":"before a reject or a rename, count the findings it would create across the corpus; a word in ordinary use or a language keyword gets a qualifying rename instead of a bare rejection"},{"text":"propose, then apply with because and over; a human ruling carries the human's words with --human, and none is ever invented"},{"text":"declare a new noun before any code, spec, or record uses it"},{"text":"update every concept whose definition or related list names the changed one"},{"text":"rename once, everywhere: files, commands, modules, Scope views, npm scripts, and refuse the old name with a one-line migration"},{"text":"run the vocabulary check","leaves":"lexicon check with 0 rejected names and 0 unknown nouns"}],"pitfalls":["rejecting a bare word turned 227 uses of the TypeScript keyword into findings (d-5060eaab, rt-cdcf2a29)","a fixed token ceiling was crossed and trimmed afterwards three times, and once its test was already red for the next session (d-3eb04416, d-7f5b5203, d-beedd69e, u-1c5215fe); the ceiling is gone (d-2b4c96a2)","a rejected alternative of three words or fewer becomes a name the check enforces; write it as a sentence when the word is in ordinary use (d-7c0ecc04)","a rejected name sat in a concept's related list after its concept was renamed (d-572be38e)","new nouns were left undeclared because the lexicon was outside the work order's write scope; escalate rather than leave them (u-de8416b2)"],"results":{"1":{"result":"done","evidence":"the dead end and component properties of defect open with the sentence a session needs: what it is, then where it is read"},"2":{"result":"skipped","because":"no concept was marked protected"},"3":{"result":"skipped","because":"no reject or rename"},"4":{"result":"done","evidence":"proposed lp-163c66d74f57ab90c25f0453 and lp-2b3704fa1299b7e947ef4946, applied with because and over (d-d5bea2db, d-b66f940f); no human ruling, so no --human"},"5":{"result":"deviated","because":"the dead-end code and spec bullets were written before the properties were applied in the same session; the properties landed before anything was recorded under the name outside this session's decisions"},"6":{"result":"done","evidence":"defect's convergence property and orient's definition now name dead ends; docs/journal.md describes both"},"7":{"result":"skipped","because":"no rename"},"8":{"result":"done","evidence":"npm run -s lexicon:check: 0 rejected names, 0 unknown nouns (629 files)"}},"binding":"none: this session owns no active work order"} +{"id":"d-7a142d11","kind":"decision","at":"2026-10-27T18:05:07.721Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"the CI check's pull request report does not name dead ends in this change","over":["a section of the CI report beside the bugs that came back"],"because":"the brief named orient, spec --check, the convergence reading and escalation; the CI report has its own plain-words wording and tests, and spec --check, which CI runs, already prints the DEAD END line","binding":"none: this session owns no active work order"} +{"id":"d-d45b0c66","kind":"decision","at":"2026-10-27T18:05:07.988Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"chose":"a defect written before the component field gets no later record giving it one; the reading derives and counts it","over":["letting classify give a component, as it gives a class"],"because":"the owner asked that older records be derived from their files and counted, never dropped; classify giving a component is the append-only way to place the 20 unplaced defects and is left for a later change","binding":"none: this session owns no active work order"} +{"id":"en-d4d054c9","kind":"enactment","at":"2026-10-27T18:05:13.939Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","commit":"887abd8","dirty":true,"practice":"src/journal/hand back delegated work","version":"817de802","trigger":"explicit","steps":[{"text":"record each choice the brief did not fix as a decision, with the alternative in --over and the cost in --because","leaves":"the decisions' ids"},{"text":"record each limit, accepted risk or case you judged acceptable as a decision when you chose it, a conjecture when you are unsure of it, and unable when you did not do it","leaves":"the records' ids"},{"text":"write the report citing each record by its id instead of restating the judgment; a judgment in the report with no record is the report's defect","leaves":"the report, every judgment in it citing a record"},{"text":"as the coordinator, read the delegate's records before its report: journal --session "}],"pitfalls":["a delegated agent judged a false spec problem accurate in its report and recorded nothing, so only a careful reading of the report caught it (df-384acb1e)"],"results":{"1":{"result":"done","evidence":"d-9ddcfea6, d-23d90bee, d-673c5a2e, d-e6d763a3, d-9ada9470, d-777c1614, d-b66c7fec, d-6beb305a, d-29f52b0c, d-0f7f9434; d-b95d2eb5 and d-eabb7952 retracted (rt-745246f5, rt-8c4404d4)"},"2":{"result":"done","evidence":"limits as decisions: d-7a142d11 (no CI report section), d-d45b0c66 (old records not re-placed by a later record)"},"3":{"result":"done","evidence":"the report cites each record by id"},"4":{"result":"skipped","because":"I am the delegate; the coordinator reads journal --session aa78b6ceaeb4845e0"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/ad8520a8703d71a7b.a90f13df.jsonl b/.coherence/journal/ad8520a8703d71a7b.a90f13df.jsonl new file mode 100644 index 00000000..d0ae1d1b --- /dev/null +++ b/.coherence/journal/ad8520a8703d71a7b.a90f13df.jsonl @@ -0,0 +1,3 @@ +{"id":"en-d570ddc1","kind":"enactment","at":"2026-10-26T23:33:05.643Z","session":"ad8520a8703d71a7b","agent":"general-purpose","commit":"c30c378","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"refute src/plugins/a qualified use narrows a whole-module import; refute src/plugins/Go is read through its parser","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"both bullets green batched and alone (run ad8520a8703d71a7b.049d02d2, first pass)"},"2":{"result":"done","evidence":"one line each: languages.ts treeSlot used := undefined; plugin.json privateName ^[^A-Z]; diff read before each refute"},"3":{"result":"done","evidence":"each red on its own AssertionError (expected Row/seal joins, got whole; Γ read not exported), run directly to read it"},"4":{"result":"done","evidence":"restored from copies taken before each break, cmp equal"},"5":{"result":"done","evidence":"both green batched and alone again in the same run file"},"6":{"result":"skipped","because":"both reds came from the breaks"}},"binding":"none: this session owns no active work order"} +{"id":"d-ae06d88c","kind":"decision","at":"2026-10-26T23:33:13.273Z","session":"ad8520a8703d71a7b","agent":"general-purpose","commit":"c30c378","dirty":true,"chose":"Go's import names come from qualified uses the core pairs with imports: captures @use.qualifier/@use.name, TreeReader.uses, and an optional ModuleResolution.boundName (default: the specifier's last path element); dot and blank imports capture their . and _ as the alias, so no use narrows them","over":["read Go imports whole through the parser, joining every file of an imported package","keep a hand-written Go import reader beside the parser"],"because":"the old reader joined an import only to the package file declaring the used name; whole imports would over-join every package file in mass and the economy, and a second reader is what the one-reader rule refuses; over the Go standard library the pairing differs from the old reader in 6 places it was right (variadic ...pkg.T) and none where it is wrong outside 3 files the grammar cannot parse","binding":"none: this session owns no active work order"} +{"id":"d-f1696eae","kind":"decision","at":"2026-10-26T23:33:13.532Z","session":"ad8520a8703d71a7b","agent":"general-purpose","commit":"c30c378","dirty":true,"chose":"Go's privateName is ^\\P{Lu}, read with the u flag the core now gives privateName","over":["an ASCII ^[^A-Z] privateName"],"because":"Go exports a name whose first letter is Unicode upper case (Lu), as the old reader's exported() said; an ASCII rule would read Γ unexported","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/ae41053f3d446b86f.079c7659.jsonl b/.coherence/journal/ae41053f3d446b86f.079c7659.jsonl new file mode 100644 index 00000000..8d7640f3 --- /dev/null +++ b/.coherence/journal/ae41053f3d446b86f.079c7659.jsonl @@ -0,0 +1,2 @@ +{"id":"d-b3f1766c","kind":"decision","at":"2026-10-26T23:17:28.546Z","session":"ae41053f3d446b86f","agent":"general-purpose","commit":"f76b1e0","dirty":true,"chose":"Rust use trees and inline modules are read through a new @import.prefix capture: the core joins, outer first, every prefix whose parent node holds an import's specifier (after the prefix) to that specifier with the manifest's treeSitter.separator (Rust's ::); rust.scm captures a scoped_use_list's path, and an inline mod's mod keyword, as prefixes","over":["a plugin hook that turns a captured use tree's text into specifiers (a hand-written reader of use-tree text again), and fixed-depth query patterns with repeated captures (bounded nesting, patterns multiplying per depth)"],"because":"composition by the tree's own nesting reads any depth with one pattern per leaf shape, keeps the plugin reading no text, and is general to any language with grouped imports (Rust, PHP group use, Scala); the mod keyword prefix lets resolution know a use sits in an inline module (mod tests { use super::* }), which the line reader resolved one module too high","binding":"none: this session owns no active work order"} +{"id":"d-65ca964c","kind":"decision","at":"2026-10-26T23:25:54.264Z","session":"ae41053f3d446b86f","agent":"general-purpose","commit":"f76b1e0","dirty":true,"chose":"demote src/adapters/a Rust line declares its items: moved to src/adapters/a Rust file declares its top-level items","over":["keeping the name a Rust line declares its items over a claim no longer about lines"],"because":"Rust's declarations are read through its parser now, a file at a time: the bullet is restated under a name that says what it claims, refuted again under that name","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/ae41053f3d446b86f.8596103a.jsonl b/.coherence/journal/ae41053f3d446b86f.8596103a.jsonl new file mode 100644 index 00000000..f1a367b8 --- /dev/null +++ b/.coherence/journal/ae41053f3d446b86f.8596103a.jsonl @@ -0,0 +1,7 @@ +{"id":"en-2c65dd32","kind":"enactment","at":"2026-10-26T23:33:14.154Z","session":"ae41053f3d446b86f","agent":"general-purpose","commit":"f76b1e0","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl, batched pass and each alone pass for src/adapters/a Rust file declares its top-level items"},"2":{"result":"done","evidence":"dropped @exported from the fn pattern in rust.scm (one line, diff read)"},"3":{"result":"done","evidence":"refute src/adapters/a Rust file declares its top-level items recorded red in .coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl; ERR_ASSERTION: seal read as private (+false -true)"},"4":{"result":"done","evidence":"cmp against the copy taken before the break: plugins/rust/rust.scm identical"},"5":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl second run, 4 pass batched, 4 pass alone"},"6":{"result":"done","evidence":"the red came from the break (its own assertion), no correction needed"}},"binding":"none: this session owns no active work order"} +{"id":"en-afa611ae","kind":"enactment","at":"2026-10-26T23:33:14.574Z","session":"ae41053f3d446b86f","agent":"general-purpose","commit":"f76b1e0","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl, batched pass and each alone pass for src/adapters/a Rust use is read in code alone"},"2":{"result":"done","evidence":"deleted the scoped_use_list @import.prefix line in rust.scm (one line, diff read)"},"3":{"result":"done","evidence":"refute src/adapters/a Rust use is read in code alone recorded red in .coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl; ERR_ASSERTION: Row from store for Row from crate::store"},"4":{"result":"done","evidence":"cmp against the copy taken before the break: plugins/rust/rust.scm identical"},"5":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl second run, 4 pass batched, 4 pass alone"},"6":{"result":"done","evidence":"the red came from the break (its own assertion), no correction needed"}},"binding":"none: this session owns no active work order"} +{"id":"en-b21f971a","kind":"enactment","at":"2026-10-26T23:33:14.978Z","session":"ae41053f3d446b86f","agent":"general-purpose","commit":"f76b1e0","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl, batched pass and each alone pass for src/adapters/a Rust use in an inline module is read from that module"},"2":{"result":"done","evidence":"deleted the inline mod prefix line in rust.scm (one line, diff read)"},"3":{"result":"done","evidence":"refute src/adapters/a Rust use in an inline module is read from that module recorded red in .coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl; ERR_ASSERTION: * <- src/lib.rs where src/store/mod.rs expected"},"4":{"result":"done","evidence":"cmp against the copy taken before the break: plugins/rust/rust.scm identical"},"5":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl second run, 4 pass batched, 4 pass alone"},"6":{"result":"done","evidence":"the red came from the break (its own assertion), no correction needed"}},"binding":"none: this session owns no active work order"} +{"id":"en-c8b3fc52","kind":"enactment","at":"2026-10-26T23:33:15.384Z","session":"ae41053f3d446b86f","agent":"general-purpose","commit":"f76b1e0","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl, batched pass and each alone pass for src/plugins/a path a group spells in pieces is read whole"},"2":{"result":"done","evidence":"made speller return the node text alone (one line, diff read)"},"3":{"result":"done","evidence":"refute src/plugins/a path a group spells in pieces is read whole recorded red in .coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl; ERR_ASSERTION: json for A::json"},"4":{"result":"done","evidence":"cmp against the copy taken before the break: src/plugins/syntax-trees.ts identical"},"5":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl second run, 4 pass batched, 4 pass alone"},"6":{"result":"done","evidence":"the red came from the break (its own assertion), no correction needed"}},"binding":"none: this session owns no active work order"} +{"id":"en-096b7781","kind":"enactment","at":"2026-10-26T23:38:26.954Z","session":"ae41053f3d446b86f","agent":"general-purpose","commit":"f76b1e0","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.cbacda01.jsonl first run, pass batched and alone"},"2":{"result":"done","evidence":"census statement read from its own match only (one line, diff read)"},"3":{"result":"done","evidence":"refute recorded red in .coherence/runs/ae41053f3d446b86f.cbacda01.jsonl; ERR_ASSERTION missing inside a block"},"4":{"result":"done","evidence":"cmp against the copy: src/plugins/syntax-trees.ts identical"},"5":{"result":"done","evidence":".coherence/runs/ae41053f3d446b86f.cbacda01.jsonl later run, pass batched and alone"},"6":{"result":"done","evidence":"the red came from the break, no correction needed"}},"binding":"none: this session owns no active work order"} +{"id":"d-36214c3b","kind":"decision","at":"2026-10-26T23:39:23.431Z","session":"ae41053f3d446b86f","agent":"general-purpose","commit":"f76b1e0","dirty":true,"chose":"Rust's parser reading names a raw identifier as written (r#match) and reads a trait as a type to the interface map as declares already did","over":["stripping r# as the line reader did, and keeping isTypeDeclaration false for a trait"],"because":"rust-analyzer reports fn r#match as r#match (plugin calibrate: 13 of 13 on a fixture holding one), and the line reader's two slots disagreed about a trait (declares type, interfaces no type), which one parse cannot; neither occurs at the top level of hexyl or PostHog's rust/ (15,683 declarations identical)","binding":"none: this session owns no active work order"} +{"id":"d-de9139de","kind":"decision","at":"2026-10-26T23:39:23.700Z","session":"ae41053f3d446b86f","agent":"general-purpose","commit":"f76b1e0","dirty":true,"chose":"Rust's entrance and lists slots (#156's foreign exports, examples, rustListOf, and binds) keep reading text through rust-source.ts's line helpers","over":["moving them onto the parse in this change"],"because":"a plugin reaches the parse only through the captures the core reads (imports, declarations); foreign exports need impl headers, attributes and cfg(test) bodies, and lists a literal's members, which would need a core interface for a plugin to query its own syntax tree, not a contained change","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/af6128b7afd884689.d846b593.jsonl b/.coherence/journal/af6128b7afd884689.d846b593.jsonl new file mode 100644 index 00000000..0e9556e9 --- /dev/null +++ b/.coherence/journal/af6128b7afd884689.d846b593.jsonl @@ -0,0 +1,10 @@ +{"id":"d-e0d78a54","kind":"decision","at":"2026-10-27T19:19:27.260Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"correct d-a59ee38f: its premise that nothing but the test fixtures fills the hand-written reader slots is false. Every bundled language manifest of Coherence 1.10.1 (python, go, rust, typescript) is pluginApi 2 and fills source, declares and topLevel by hand, so every copy plugin eject made from 1.10 or before fills them, as does any plugin written from the 1.10 guide. This release still refuses them (the owner's forced migration stands), but in one problem per plugin naming every slot, the ejected copy's recovery first (set its entry to bundled, eject it again from this version into a new folder, reapply the changes), said plainly as ejected from an older Coherence when its name is a bundled plugin's, and the parser path after for a plugin written from scratch; plugin.ts PLUGIN_API_CHANGES[4] and docs/plugins.md say the same","over":["let a pluginApi 2 copy keep loading its hand-written readers for one more release","keep d-a59ee38f's refusal text, which named only the parser path"],"because":"the blind review reproduced three PROBLEMs and exit 1 from spec --check on a real 1.10.1 eject; the owner chose forced migration, so the remedy is a refusal that tells the copy's owner the one command that migrates it, held by a test over a byte-for-byte 1.10.1 eject (src/plugins/fixtures/ejected-1.10.1/typescript)","binding":"none: this session owns no active work order"} +{"id":"d-8450fe5c","kind":"decision","at":"2026-10-27T19:19:46.234Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"an interfaces table states its language's facts alone (INTERFACE_FACTS: serverBounds): SyntaxTables.interfaces is InterfaceFacts, the type declarations, default exports, import lists and wildcard imports the Structure reading and the kept answers read are parsedOf(language, \"interfaces\") alone, and a table (a provider's, or an extending plugin's wrap) that answers any other member is refused naming each when the slot loads, whether or not its plugin names a parser; the bundled Rust table drops its isDefaultExport and defaultNames constants, which the parse answers the same","over":["refuse only importLists and wildcardModules, as the review asked, leaving isTypeDeclaration, isDefaultExport and defaultNames to a table that could override the parse through the spread over it","ignore a table's readers silently, which the core can no longer read anyway"],"because":"the blind review's probe showed a pluginApi 4 plugin with no parser answering what the removed kept slot answered through syntaxOf(zz, interfaces).wildcardModules; the other three members were the same shape, a hand reader that overrode the parse for a parser plugin. With the readings typed out of the slot, the core cannot read a table's reader (the typecheck refuses it); the refusal tells the author it went unread (d-a5c35add)","binding":"none: this session owns no active work order"} +{"id":"d-c2adc1bf","kind":"decision","at":"2026-10-27T19:19:46.516Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"docs/plugins.md claims exactly what the slots read: no slot answers a reading of the language's declarations, imports or exports, and the entrances slot (candidates, definitionAt, continues, binds, importedAmong) and the lists slot still read a file's text by hand for what the parse does not derive; plugin-docs.test.ts holds the interfaces row and the refused readings to INTERFACE_FACTS and the parse's interfaces reading, and the entrance members named to the entrance syntax","over":["refuse entrances.binds and importedAmong now and derive them from the parse"],"because":"binds answers a different question per language (Go: whether a name is bound locally by := or a var inside a function; TypeScript: any const, let or destructuring, local ones too), which no bundled query captures; deriving it is a change to entrance detection in four languages, not a correction of a claim, so the guide says what is true and the overlap is named rather than hidden","binding":"none: this session owns no active work order"} +{"id":"d-507d7fe9","kind":"decision","at":"2026-10-27T19:19:46.791Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"tell an ejected bundled plugin apart by its name: a plugin by path named as a bundled one is a copy eject made, since eject keeps the manifest's name and the config's key must match it","over":["match its files' digests against every bundled release's files"],"because":"the digests of every release's plugin files would have to ship and grow with each release, and an edited copy (the point of ejecting) matches none of them; a name is what eject keeps and the registry already requires to equal the key. A plugin of another name is still told the eject recovery first, conditionally","binding":"none: this session owns no active work order"} +{"id":"d-bd7ea31a","kind":"decision","at":"2026-10-27T19:19:47.067Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"keep the real 1.10.1 eject as a fixture at src/plugins/fixtures/ejected-1.10.1/typescript, byte for byte as Coherence 1.10.1's plugin eject wrote it (imports rewritten to @posthog/coherence/plugin), with tsconfig.json excluding that folder from the typecheck","over":["rebuild the copy in the test from git show v1.10.1:plugins/typescript","keep its plugin.json alone"],"because":"a tag lookup fails in a shallow CI clone, and the manifest alone is not the copy a user holds; its modules import @posthog/coherence/plugin, which resolves to no types in a checkout, so the typecheck leaves the folder out as the build already leaves fixtures out (tsconfig.build.json)","binding":"none: this session owns no active work order"} +{"id":"d-4f873bce","kind":"decision","at":"2026-10-27T19:19:47.342Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"plugin check's answers agree duty now compares two parse-derived readings, the interfaces reading of a declaration's line alone and the declares reading of the whole text; its test provokes a disagreement with queries that read a decorated class as a type and an undecorated one as a body","over":["drop the type-declaration comparison, since no plugin table answers it any more"],"because":"an interfaces table can no longer state isTypeDeclaration, so the old fixture is refused; queries that read a declaration by what surrounds it are still a fault the duty finds, and the duty keeps its refutation","binding":"none: this session owns no active work order"} +{"id":"d-a1045837","kind":"decision","at":"2026-10-27T19:19:56.981Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"demote src/plugins/no core code reads a hand-written reader slot: retired; what it claimed is held at the registry and restated in src/plugins/a language read through a parser has one reader of its text: a manifest filling a removed slot never loads (readManifest, which every manifest the core loads passes through), so no core read can see one","over":[],"because":"the bullet's test scanned src's text for the shapes of a read, the text matching this branch abandoned elsewhere: three rewrites of keptModules typechecked and passed it (a computed slot name through a cast, \"kept\" held in a variable, and const { kept } = sourceProvider(...)?.manifest.syntax). A scan of input the checked code controls proves nothing (d-a5c35add); the refusal at the registry does, since no manifest that fills a removed slot reaches the core, whatever a module spells","binding":"none: this session owns no active work order"} +{"id":"d-27dfe15d","kind":"decision","at":"2026-10-27T19:20:04.562Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"correct d-581051d3: its claim that the parse test in syntax-trees.test.ts refuses the shapes a cast could hide was false, and the commit's (2558929) claim that a test fails on any read of a hand-written slot, a cast among them, with it. The typecheck refuses a read of the four names as slots, since SyntaxSlot and SyntaxTables name none; the scan never held the rest (a computed name through a cast, a name held in a variable, a destructured kept passed it), and is dropped. What holds is the registry: a manifest that fills a removed slot never loads, so whatever a core module spells, no manifest it could read one off holds one (src/plugins/a language read through a parser has one reader of its text, refuted by letting kept through the refusal)","over":["strengthen the scan to follow variables and destructuring"],"because":"a scan of the core's text for the shapes of a read searches for the bad state rather than leaving it inexpressible, and each new spelling is one more it must know (d-a5c35add); the refusal is a single door every manifest passes","binding":"none: this session owns no active work order"} +{"id":"en-58df6a7a","kind":"enactment","at":"2026-10-27T19:21:54.907Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant of the four changed src/plugins bullets --each, pass batched and alone (.coherence/runs/6a157d1b-4fba-441c-b247-618d60e996ba.d2cf7b16.jsonl)"},"2":{"result":"done","evidence":"four one-line breaks, each diffed against its copy: kept let through the registry refusal, bundledEjected bypassed, statedFacts unrefused, answersAgree type comparison skipped"},"3":{"result":"done","evidence":"refute recorded red for each in .coherence/runs/af6128b7afd884689.4da4c79c.jsonl, each test failing on its own assertion, run alone with the break to read it"},"4":{"result":"done","evidence":"restored from copies in the scratchpad, cmp silent each time"},"5":{"result":"done","evidence":"run --invariant of the four --each, pass batched and alone (.coherence/runs/af6128b7afd884689.4da4c79c.jsonl)"},"6":{"result":"skipped","because":"every red came from its break"}},"binding":"none: this session owns no active work order"} +{"id":"d-a33fbc0f","kind":"decision","at":"2026-10-27T19:22:02.420Z","session":"af6128b7afd884689","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"fix this review's interfaces finding by changing the representation, not by a narrower door: the interfaces slot's type is InterfaceFacts (serverBounds alone) and its readings moved to parsedOf, so the core cannot read a table's reader (the typecheck refuses it); the two bullets added to src/plugins (an ejected copy is told to eject again, an interfaces table states facts alone) hold the refusal messages a plugin's author reads, not a search of the core. Whether src/plugins as a whole needs the redesign its dead end asks about is left to the owner","over":["add a scan for interfaces-table reads beside the dropped slot scan"],"because":"spec --check names src/plugins a dead end (26 defects, 7 classes, 12 back through a guard it had) and asks to weigh a different design before a narrower door; this round's principle (d-a5c35add) is the same, and an escalation is the owner's to answer, not a delegated agent's","binding":"none: this session owns no active work order"} diff --git a/.coherence/journal/af6680f06b4959bd8.75d4aaa6.jsonl b/.coherence/journal/af6680f06b4959bd8.75d4aaa6.jsonl new file mode 100644 index 00000000..f1a84855 --- /dev/null +++ b/.coherence/journal/af6680f06b4959bd8.75d4aaa6.jsonl @@ -0,0 +1,14 @@ +{"id":"d-f38cc0e5","kind":"decision","at":"2026-10-27T19:13:49.128Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"the dead-end reading counts every defect placed in a subsystem after its first guard, open or closed however closed, and tells a dead end from converging work by rising arrivals: the later half of its rounds must bring at least one more defect than the earlier half (DEAD_END.rise 1), beside 8 defects, 3 classes and 3 rounds","over":["returns through a guard name a close reuses, which an agent controls by naming a fresh guard or leaving the defect open","magnitude alone (16 defects, 8 rounds): src/plugins would trip only after b19875c, and src/lifecycle peaked at 13","arrivals not falling (later at least earlier): src/lifecycle trips at 2026-10-12 with rounds of 3, 2, 2, 3"],"because":"a check must never trust input the checked thing controls (d-a5c35add), and a round's commit is git's HEAD at the write, not a word an agent chooses; replayed every six hours from 2026-09-20 over every worktree's journal, src/plugins trips at 2026-10-27T06:00 as before (13 defects, 7 classes, 9 rounds, 4 against 8), src/lifecycle peaks at 13 defects, 7 classes, 6 rounds with 7 against 6 and comes closest at 2026-10-12 with 5 against 5, src/readings/scope peaks at 10, 5, 6 with 7 against 3; every other component stays below 4 defects","binding":"none: this session owns no active work order"} +{"id":"d-98236f10","kind":"decision","at":"2026-10-27T19:14:08.791Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"a defect with no class counts toward a dead end, the unclassified together as one more class, and every reading (spec --check, orient, query convergence) names the unclassified defects of its window by id","over":["requiring --class at the write, which would end classifying after the fact (classify) that the close a defect practice teaches","counting an unclassified defect and adding no class, so leaving --class off kept a subsystem under the class threshold and out of every guard failure"],"because":"leaving --class off was a way an agent's report silenced both alarms (d-a5c35add); counted as its own class it adds to the alarm instead, and named by id it is visible where the guard failure cannot see it","binding":"none: this session owns no active work order"} +{"id":"d-460d19b7","kind":"decision","at":"2026-10-27T19:14:09.076Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"defect refuses a --component that does not own every file the defect names, a file's owner being the deepest component folder above it; a file in no component or outside the project has no owner, so it leaves the record with no component without --component and is refused with it","over":["allowing a differing --component with a reason: no case was found where one must differ, since a fault whose files span components counts toward each by derivation","keeping the root-dropping rule, which gave a component to a defect whose other file it did not hold"],"because":"an explicit component that disagrees with the files moved a defect out of the subsystem that holds the fault (review of 2558929, d-a5c35add); with the files deciding, a wrong component cannot be written, and the claim that the component owns every file is true","binding":"none: this session owns no active work order"} +{"id":"d-d1f782bb","kind":"decision","at":"2026-10-27T19:14:09.359Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"only an acknowledgement carrying --human restarts a dead end's count; an escalation is awaiting a human until anyone acknowledges it, and one an agent acknowledged without --human leaves the reading asking for a new escalation","over":["any acknowledgement restarting the count, which let the agent under watch silence its own alarm","refusing an agent's acknowledgement of a dead-end escalation at the verb, which would make acknowledge read the dead-end reading"],"because":"the acknowledgement is the alarm's off switch, and the person it is for is the human (d-a5c35add); --human records the words the agent attributes to one, the strongest attribution the journal has","binding":"none: this session owns no active work order"} +{"id":"d-5a93b730","kind":"decision","at":"2026-10-27T19:14:09.660Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"loadJournalAcrossWorktrees reads every store file of every other worktree and skips one only when its bytes equal a file already read (compared within files of the same length); a file it cannot read is reported as damaged and stands for nothing","over":["skipping a file by its name and size, which dropped a different file of equal size and let an unreadable file hide its namesakes","a sha256 digest of each file: measured about 300 ms against about 250 ms for the byte comparison","parsing every file and deduping by record id alone, which splits and hashes every line of 150 MB"],"because":"a skip must rest on the content, not on what a file is called; over this repository's 106 worktrees (about 150 MB of journals) the reading took about 250 ms warm against 149 ms before, 1644 records, damaged 0","binding":"none: this session owns no active work order"} +{"id":"d-0f96f8c6","kind":"decision","at":"2026-10-27T19:14:09.988Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"the dead-end reading and the convergence reading share one window, windowOf: the given number of whole UTC days ending today, 14 by default; query convergence --days passes its days to the dead ends, and both print from and to","over":["a rolling 14 times 24 hours for the dead ends beside whole days for the convergence reading, which named different first days and ignored --days"],"because":"two readings in one report over different windows disagree about the same defect (review of 2558929)","binding":"none: this session owns no active work order"} +{"id":"d-40784fb2","kind":"decision","at":"2026-10-27T19:14:10.311Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"a practice trigger defect fires when one simple command runs Coherence's defect, classify or resolved verb, named after its program, with --class ; keep state where it is true fires on defect duplicated-fact and explicit, and its invariants line names the trigger's own invariant (src/spec/a practice fires on a defect's class)","over":["a command trigger naming --class: a command trigger's words are adjacent, and the defect verb's next word is free text","firing on every defect as before, which delivered a practice about where state lives on cost and audience defects","dropping the invariants line: the practice is kept true by the trigger that delivers it"],"because":"d-fd38bffc promised a trigger by defect class with the dead-end alarm; a defect trigger naming a class no lexicon declares could never fire, so the model names it as a problem","binding":"none: this session owns no active work order"} +{"id":"d-5d94248c","kind":"decision","at":"2026-10-27T19:14:10.590Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"orient prints one line of the dead-end reading when no subsystem is at a dead end and any worktree's journal holds a defect: the worktrees read, the placement and the unclassified defects","over":["printing nothing without a dead end, which hid which journals were read and the unclassified defects"],"because":"an alarm that says nothing cannot be told from an alarm that read nothing (review of 2558929)","binding":"none: this session owns no active work order"} +{"id":"d-78adbb30","kind":"decision","at":"2026-10-27T19:15:31.145Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"amend src/journal/close a defect: step 3 lists the doors first, as what a fix that leaves the code no way to express the bug looks like, then says that when the dead-end reading names the defect's component a different design is weighed before any such door, the choice recorded as a decision","over":["the inserted dead-end clause before the list of doors, which read as if the doors described the decision"],"because":"a blind review of 2558929 read the list as the decision's content; the step's meaning is unchanged","cites":["en-609df1d8"],"binding":"none: this session owns no active work order"} +{"id":"d-35bc4af2","kind":"decision","at":"2026-10-27T19:15:31.444Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"amend src/journal/keep state where it is true: it fires on defect duplicated-fact and explicit instead of on every defect recorded, and its invariants line names src/spec/a practice fires on a defect's class instead of a defect carries its class and origin","over":["firing on every defect, which delivered it on cost and audience defects"],"because":"d-fd38bffc promised a trigger by defect class with the dead-end alarm (d-40784fb2); the invariant it named was unrelated to the practice","cites":["en-c940fd6a"],"binding":"none: this session owns no active work order"} +{"id":"d-7d8c079b","kind":"decision","at":"2026-10-27T19:22:48.992Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"chose":"correct d-98236f10: each unclassified defect counts toward a dead end as a class of its own, not the unclassified together as one","over":["the unclassified together as one more class, under which a subsystem whose later defects all carry no class stays under the three-class threshold"],"because":"the reviewer's probe (gaming.ts, no --class on any later defect) still named no dead end with the unclassified as one class; an unclassified defect could be of any class, so counting each as its own is the reading no omission can lower (d-a5c35add)","cites":["d-98236f10"],"binding":"none: this session owns no active work order"} +{"id":"en-24ada3a5","kind":"enactment","at":"2026-10-27T19:31:53.628Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant for the five bullets --each before any break: 5 pass batched, 5 pass alone (.coherence/runs/af6680f06b4959bd8.14b51916.jsonl)"},"2":{"result":"done","evidence":"eight one-line breaks, each diffed against a pre-break copy: count only guarded closes; any acknowledgement answers; unclassified as one class; rise threshold dropped; --component checked only against files in no component; a file in no component passed over; skip by length; prunable kept; --class read from any command"},"3":{"result":"done","evidence":"eight refute records, each red on its own assertion confirmed by running the test with the break staged (the DEAD END line, the agent acknowledgement, the every-class-removed reading, the arrivals-fell assertion, exit 0 where 1, the widget record, the second legacy record, the prunable record, decide firing)"},"4":{"result":"done","evidence":"each file copied back from the pre-break copy; cmp equal for dead-ends.ts, verbs.ts, store.ts and practice.ts"},"5":{"result":"done","evidence":"run --invariant for the five bullets --each after: 5 pass batched, 5 pass alone, every one passed alone"},"6":{"result":"skipped","because":"every red came from the staged break, confirmed by the failing assertion"}},"binding":"none: this session owns no active work order"} +{"id":"rt-24eefb6b","kind":"retraction","at":"2026-10-27T19:32:02.018Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"of":"en-24ada3a5","because":"it counted eight breaks and refutations where nine were staged and recorded","binding":"none: this session owns no active work order"} +{"id":"en-9583b462","kind":"enactment","at":"2026-10-27T19:32:02.567Z","session":"af6680f06b4959bd8","agent":"general-purpose","commit":"2558929","dirty":true,"practice":"src/enforcement/witness a refutation","version":"5559d799","trigger":"command refute","steps":[{"text":"run the totality oracles being refuted in one batched run confirmed with run --each (run --invariant ... --each), and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"stage the smallest break that changes the behavior the bullet claims, not the strings the detector reads; read the diff to confirm the edit touched only the lines you meant"},{"text":"refute / --broke \"\"; the detector fails on its own assertion, not by a hang, a kill, a timeout, or what an earlier test left behind","leaves":"run record for the bullet, refutation red"},{"text":"restore the source byte for byte: from HEAD when the code under test is committed, and from a copy taken before the break when it is not","leaves":"the file matches its state before the break (git diff against HEAD, or cmp against the copy)"},{"text":"run them again in one batched run confirmed with run --each, and see each green batched and alone","leaves":"run record for the bullets, pass; per-test run record, pass"},{"text":"when the red did not come from the break, record a decision that this refutation does not count and refute again; the run store is append-only, so the correction is a later record"}],"pitfalls":["a sed matched two lines, so the test hung and went red only when it was killed (d-828ddc83)","a substring detector passed an unconditional early return that kept every expected string (df-c40bb904, x-429ed176)","the red came from the selected test depending on what earlier tests appended, not from the break (d-c4be0b1a, df-9e673484)","a self-asserted refuted: line read as witnessed, and an automatic refutation proved the instrument reports a site, not that the classifier calls it a bypass (df-b9b2711b, df-87881a8d)","a break that turns a test red when the via does not test the claim refutes nothing; record unable instead (u-2e6ee400)"],"results":{"1":{"result":"done","evidence":"run --invariant for the five bullets --each before any break: 5 pass batched, 5 pass alone (.coherence/runs/af6680f06b4959bd8.14b51916.jsonl)"},"2":{"result":"done","evidence":"nine one-line breaks, each diffed against a pre-break copy: count only guarded closes; any acknowledgement answers; unclassified as one class; rise threshold dropped; --component checked only against files in no component; a file in no component passed over; skip by length; prunable kept; --class read from any command"},"3":{"result":"done","evidence":"nine refute records, each red on its own assertion, confirmed by running the test with the break staged (the DEAD END line, the agent acknowledgement, the every-class-removed reading, the arrivals-fell assertion, exit 0 where 1, the widget record, the second legacy record, the prunable record, decide firing)"},"4":{"result":"done","evidence":"each file copied back from the pre-break copy; cmp equal for dead-ends.ts, verbs.ts, store.ts and practice.ts"},"5":{"result":"done","evidence":"run --invariant for the five bullets --each after: 5 pass batched, 5 pass alone, every one passed alone"},"6":{"result":"skipped","because":"every red came from the staged break, confirmed by the failing assertion"}},"binding":"none: this session owns no active work order"} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.073ad37a.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.073ad37a.jsonl new file mode 100644 index 00000000..b2b79084 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.073ad37a.jsonl @@ -0,0 +1,12 @@ +{"at":"2026-10-27T15:22:44.612Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":30901,"load":{"average":4.16,"cores":14},"batch":{"ms":29477},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":2505,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":120,"mode":"batched","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and the & operator keeps its own node type\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":4,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and the & operator keeps its own node type"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, and the script fetches nothing it does not check by its digest, its compiler among it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, and the script fetches nothing it does not check by its digest, its compiler among it"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":581,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":224,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":195,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":354,"mode":"batched","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":3148,"mode":"batched","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":278,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":576,"symbol":"ParseStore.of.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":588,"symbol":"ParseStore.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":596,"symbol":"ParseStore.constructor","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":835,"symbol":"StoreFolder.constructor","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":840,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":842,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":846,"symbol":"StoreFolder.all","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":848,"symbol":"StoreFolder.all","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":849,"symbol":"StoreFolder.all","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":849,"symbol":"StoreFolder.all.map() callback","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":918,"symbol":"StoreFolder.readWithFirstLine.firstLine","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":932,"symbol":"StoreFolder.firstLine","class":"inside","of":"chokepoint","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":638,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:811 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["StoreFolder in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":15,"mode":"batched","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29477,"reason":"1 test under \"a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":12,"mode":"batched","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T15:27:22.112Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":277130,"load":{"average":5.89,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25323,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24768,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads TypeScript'\\''s imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24577,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and the & operator keeps its own node type' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and the & operator keeps its own node type"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24731,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build\\.sh builds: each is byte for byte the digest the script records and checks its build against, and the script fetches nothing it does not check by its digest, its compiler among it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, and the script fetches nothing it does not check by its digest, its compiler among it"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25413,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25284,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path, at \\.coherence, at its parses or at a plugin'\\''s folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25013,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up or speak at a session start: a folder where the store'\\''s file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25094,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a log line is read only where it signs itself with this machine'\\''s key, a torn line is passed over, and a log that fails more than a torn line'\\''s worth is read no further, so a repository'\\''s log costs a few signatures whatever its size' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27839,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log'\\''s path never holds a process up, and a key file too short to be one is replaced' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24624,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees\\.ts outside StoreFolder reads Coherence'\\''s own files or the machine key, and only StoreFolder spells the store'\\''s folder' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24419,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a store'\\''s generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T15:37:26.377Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":34250,"load":{"average":7.43,"cores":14},"batch":{"ms":32736},"invariants":[{"component":"src/adapters","name":"only the project's files","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"1 test under \"only the project's own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":857,"mode":"batched","state":"invariant","enforces":["only the project's own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass"]},{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"1 test under \"a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":85,"mode":"batched","state":"requirement","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names"]},{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"1 test under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":3198,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"1 test under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"requirement","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"no test ran under the name \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and the & operator keeps its own node type\" in node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and the & operator keeps its own node type"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"no test ran under the name \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, and the script fetches nothing it does not check by its digest, its compiler among it\" in node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, and the script fetches nothing it does not check by its digest, its compiler among it"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":251,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"1 test under \"a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":319,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"1 test under \"a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":3198,"mode":"batched","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":278,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":576,"symbol":"ParseStore.of.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":588,"symbol":"ParseStore.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":596,"symbol":"ParseStore.constructor","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":835,"symbol":"StoreFolder.constructor","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":840,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":842,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":846,"symbol":"StoreFolder.all","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":848,"symbol":"StoreFolder.all","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":849,"symbol":"StoreFolder.all","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":849,"symbol":"StoreFolder.all.map() callback","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":932,"symbol":"StoreFolder.readWithFirstLine.firstLine","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":946,"symbol":"StoreFolder.firstLine","class":"inside","of":"chokepoint","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":702,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:811 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["StoreFolder in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"1 test under \"the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":24,"mode":"batched","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32736,"reason":"1 test under \"a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":13,"mode":"batched","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T15:42:09.066Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":282238,"load":{"average":6.38,"cores":14},"invariants":[{"component":"src/adapters","name":"only the project's files","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25570,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='only the project'\\''s own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["only the project's own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass"]},{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24787,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names"]},{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28027,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25304,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='Coherence'\\''s folder in the user'\\''s configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/\\.config, so the machine key never lands in whatever folder a process starts in' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24762,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and the & operator keeps its own node type' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and the & operator keeps its own node type"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24991,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build\\.sh builds: each is byte for byte the digest the script records and checks its build against, and the script fetches nothing it does not check by its digest, its compiler among it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, and the script fetches nothing it does not check by its digest, its compiler among it"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25318,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path, at \\.coherence, at its parses or at a plugin'\\''s folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25340,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up or speak at a session start: a folder where the store'\\''s file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27911,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log'\\''s path never holds a process up, and a key file too short to be one is replaced' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24931,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees\\.ts outside StoreFolder reads Coherence'\\''s own files or the machine key, and only StoreFolder spells the store'\\''s folder' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25249,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a store'\\''s generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T15:43:05.253Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":33997,"load":{"average":5.45,"cores":14},"batch":{"ms":32474},"invariants":[{"component":"src/adapters","name":"only the project's files","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"only the project's own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":848,"mode":"batched","state":"invariant","enforces":["only the project's own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass"]},{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":75,"mode":"batched","state":"requirement","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names"]},{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":3000,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"requirement","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":73,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":248,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":266,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":3156,"mode":"batched","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sitesRef":{"hash":"sha256:25e496ba80b9c28e538826a03bd466fb67e8605de3a9186ec9d2e3af069059c5","at":"2026-10-27T15:37:26.377Z"},"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":700,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:811 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["StoreFolder in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":24,"mode":"batched","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32474,"reason":"1 test under \"a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":13,"mode":"batched","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T15:47:48.067Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":282504,"load":{"average":4.67,"cores":14},"invariants":[{"component":"src/adapters","name":"only the project's files","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25486,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='only the project'\\''s own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["only the project's own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass"]},{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24734,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names"]},{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28152,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25361,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='Coherence'\\''s folder in the user'\\''s configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/\\.config, so the machine key never lands in whatever folder a process starts in' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25389,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25029,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build\\.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI'\\''s verify waits on the job that runs it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25115,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path, at \\.coherence, at its parses or at a plugin'\\''s folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25175,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up or speak at a session start: a folder where the store'\\''s file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28002,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log'\\''s path never holds a process up, and a key file too short to be one is replaced' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24981,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees\\.ts outside StoreFolder reads Coherence'\\''s own files or the machine key, and only StoreFolder spells the store'\\''s folder' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25041,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a store'\\''s generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T15:49:04.188Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24991,"load":{"average":3.52,"cores":14},"batch":{"ms":24664},"invariants":[{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24664,"reason":"1 of 1 tests under \"a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names\" failed: a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names","testMs":47,"mode":"batched","state":"requirement","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names"]}]} +{"kind":"refutation","at":"2026-10-27T15:49:04.489Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","broke":"took every path but a folder for a project file (isFileOnDisk in src/adapters/project-files.ts)","verdict":"fail","reason":"1 of 1 tests under \"a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names\" failed: a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names","commit":"b19875c","dirty":true} +{"at":"2026-10-27T15:49:30.509Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25444,"load":{"average":3.61,"cores":14},"batch":{"ms":25104},"invariants":[{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25104,"reason":"1 of 1 tests under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in\" failed: Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in","testMs":1,"mode":"batched","state":"requirement","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in"]}]} +{"kind":"refutation","at":"2026-10-27T15:49:30.891Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","broke":"took any XDG_CONFIG_HOME that is not empty (userConfigDir in src/lifecycle/user-dir.ts)","verdict":"fail","reason":"1 of 1 tests under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in\" failed: Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in","commit":"b19875c","dirty":true} +{"at":"2026-10-27T15:50:03.132Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25732,"load":{"average":3.64,"cores":14},"batch":{"ms":25196},"invariants":[{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25196,"reason":"1 test under \"a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":81,"mode":"batched","state":"invariant","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25196,"reason":"1 test under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in"]}]} +{"at":"2026-10-27T15:50:53.679Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"b19875c","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":50137,"load":{"average":3.88,"cores":14},"invariants":[{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25224,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, nor a path an edit names"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24881,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='Coherence'\\''s folder in the user'\\''s configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/\\.config, so the machine key never lands in whatever folder a process starts in' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.19edb05b.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.19edb05b.jsonl new file mode 100644 index 00000000..5d0c5e2f --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.19edb05b.jsonl @@ -0,0 +1,8 @@ +{"at":"2026-10-26T22:09:41.184Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":21961,"load":{"average":3.13,"cores":14},"batch":{"ms":21660},"invariants":[{"component":"src/plugins","name":"a text reading is held to the language server's account","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21660,"reason":"1 test under \"plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":42,"mode":"batched","state":"requirement","enforces":["plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line"]},{"component":"src/plugins","name":"plugin calibrate counts misreads and what the server alone reports","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21660,"reason":"1 test under \"plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":17,"mode":"batched","state":"requirement","enforces":["plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind"]}]} +{"at":"2026-10-26T22:10:25.648Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":44192,"load":{"average":3.7,"cores":14},"invariants":[{"component":"src/plugins","name":"a text reading is held to the language server's account","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22060,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line"]},{"component":"src/plugins","name":"plugin calibrate counts misreads and what the server alone reports","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22104,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind"]}]} +{"at":"2026-10-26T22:10:48.878Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22643,"load":{"average":3.7,"cores":14},"batch":{"ms":22357},"invariants":[{"component":"src/plugins","name":"a text reading is held to the language server's account","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22357,"reason":"1 of 1 tests under \"plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line\" failed: plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line","testMs":42,"mode":"batched","state":"requirement","enforces":["plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line"]}]} +{"kind":"refutation","at":"2026-10-26T22:10:49.151Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a text reading is held to the language server's account","form":"totality oracle","broke":"let a declaration the server reports no symbol of pass (src/plugins/check.ts serverAgrees)","verdict":"fail","reason":"1 of 1 tests under \"plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line\" failed: plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line","commit":"870296d","dirty":true} +{"at":"2026-10-26T22:11:12.529Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22742,"load":{"average":4.08,"cores":14},"batch":{"ms":22453},"invariants":[{"component":"src/plugins","name":"plugin calibrate counts misreads and what the server alone reports","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22453,"reason":"1 of 1 tests under \"plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind\" failed: plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind","testMs":18,"mode":"batched","state":"requirement","enforces":["plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind"]}]} +{"kind":"refutation","at":"2026-10-26T22:11:12.802Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"plugin calibrate counts misreads and what the server alone reports","form":"totality oracle","broke":"counted every declaration the reading finds as one the server reports too (src/plugins/calibrate.ts)","verdict":"fail","reason":"1 of 1 tests under \"plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind\" failed: plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind","commit":"870296d","dirty":true} +{"at":"2026-10-26T22:11:36.215Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22932,"load":{"average":4.32,"cores":14},"batch":{"ms":22626},"invariants":[{"component":"src/plugins","name":"a text reading is held to the language server's account","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22626,"reason":"1 test under \"plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":42,"mode":"batched","state":"invariant","enforces":["plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line"]},{"component":"src/plugins","name":"plugin calibrate counts misreads and what the server alone reports","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22626,"reason":"1 test under \"plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":18,"mode":"batched","state":"invariant","enforces":["plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind"]}]} +{"at":"2026-10-26T22:12:21.668Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":45168,"load":{"average":4.39,"cores":14},"invariants":[{"component":"src/plugins","name":"a text reading is held to the language server's account","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22573,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line"]},{"component":"src/plugins","name":"plugin calibrate counts misreads and what the server alone reports","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22565,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.2a64aa4c.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.2a64aa4c.jsonl new file mode 100644 index 00000000..17e6207d --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.2a64aa4c.jsonl @@ -0,0 +1,4 @@ +{"at":"2026-10-27T18:31:13.264Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"7934a9d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25825,"load":{"average":11.43,"cores":14},"batch":{"ms":25446},"invariants":[{"component":"src/plugins","name":"no core code reads a hand-written reader slot","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25446,"reason":"1 of 1 tests under \"no core code reads a hand-written source, declares, topLevel or kept slot: the slot types name none of them, and no module reads one off a manifest's syntax, asks for one by name, or indexes a manifest's syntax by any name but a SyntaxSlot\" failed: no core code reads a hand-written source, declares, topLevel or kept slot: the slot types name none of them, and no module reads one off a manifest's syntax, asks for one by name, or indexes a manifest's syntax by any name but a SyntaxSlot","testMs":522,"mode":"batched","state":"requirement","enforces":["no core code reads a hand-written source, declares, topLevel or kept slot: the slot types name none of them, and no module reads one off a manifest's syntax, asks for one by name, or indexes a manifest's syntax by any name but a SyntaxSlot"]}]} +{"kind":"refutation","at":"2026-10-27T18:31:13.593Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"no core code reads a hand-written reader slot","form":"totality oracle","broke":"read a kept slot back in keptModules, through a cast (src/readings/scope/kept-answers.ts)","verdict":"fail","reason":"1 of 1 tests under \"no core code reads a hand-written source, declares, topLevel or kept slot: the slot types name none of them, and no module reads one off a manifest's syntax, asks for one by name, or indexes a manifest's syntax by any name but a SyntaxSlot\" failed: no core code reads a hand-written source, declares, topLevel or kept slot: the slot types name none of them, and no module reads one off a manifest's syntax, asks for one by name, or indexes a manifest's syntax by any name but a SyntaxSlot","commit":"7934a9d","dirty":true} +{"at":"2026-10-27T18:31:39.788Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"7934a9d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25862,"load":{"average":10.84,"cores":14},"batch":{"ms":25317},"invariants":[{"component":"src/plugins","name":"no core code reads a hand-written reader slot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25317,"reason":"1 test under \"no core code reads a hand-written source, declares, topLevel or kept slot: the slot types name none of them, and no module reads one off a manifest's syntax, asks for one by name, or indexes a manifest's syntax by any name but a SyntaxSlot\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":514,"mode":"batched","state":"invariant","enforces":["no core code reads a hand-written source, declares, topLevel or kept slot: the slot types name none of them, and no module reads one off a manifest's syntax, asks for one by name, or indexes a manifest's syntax by any name but a SyntaxSlot"]}]} +{"at":"2026-10-27T18:32:05.240Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"7934a9d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25122,"load":{"average":7.22,"cores":14},"invariants":[{"component":"src/plugins","name":"no core code reads a hand-written reader slot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25089,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='no core code reads a hand-written source, declares, topLevel or kept slot: the slot types name none of them, and no module reads one off a manifest'\\''s syntax, asks for one by name, or indexes a manifest'\\''s syntax by any name but a SyntaxSlot' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["no core code reads a hand-written source, declares, topLevel or kept slot: the slot types name none of them, and no module reads one off a manifest's syntax, asks for one by name, or indexes a manifest's syntax by any name but a SyntaxSlot"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl new file mode 100644 index 00000000..25e89675 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.491d0051.jsonl @@ -0,0 +1,19 @@ +{"at":"2026-10-26T21:50:53.884Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28921,"load":{"average":4.17,"cores":14},"batch":{"ms":28607},"invariants":[{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28607,"reason":"no test ran under the name \"every bundled language plugin's check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too\" in node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","mode":"batched","state":"requirement","enforces":["every bundled language plugin's check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too"]}]} +{"at":"2026-10-26T21:51:23.102Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28922,"load":{"average":4.6,"cores":14},"invariants":[{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28891,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every bundled language plugin'\\''s check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["every bundled language plugin's check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too"]}]} +{"at":"2026-10-26T21:53:53.744Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29200,"load":{"average":4.05,"cores":14},"batch":{"ms":28875},"invariants":[{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28875,"reason":"no test ran under the name \"every bundled language plugin's check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too\" in node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","mode":"batched","state":"requirement","enforces":["every bundled language plugin's check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too"]}]} +{"at":"2026-10-26T21:54:23.089Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29051,"load":{"average":3.82,"cores":14},"invariants":[{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":29021,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every bundled language plugin'\\''s check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["every bundled language plugin's check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too"]}]} +{"at":"2026-10-26T21:54:53.124Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29518,"load":{"average":3.82,"cores":14},"batch":{"ms":29194},"invariants":[{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":29194,"reason":"no test ran under the name \"every bundled language plugin's check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too\" in node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","mode":"batched","state":"requirement","enforces":["every bundled language plugin's check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too"]}]} +{"at":"2026-10-26T21:55:22.833Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29422,"load":{"average":4.06,"cores":14},"invariants":[{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":29390,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every bundled language plugin'\\''s check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["every bundled language plugin's check project names what each reading recovers, and the plugin recovers it, passing every other duty over it too"]}]} +{"at":"2026-10-26T21:56:34.113Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28997,"load":{"average":3.73,"cores":14},"batch":{"ms":28672},"invariants":[{"component":"src/plugins","name":"every bundled language plugin gives every reading","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28672,"reason":"no test ran under the name \"every bundled language plugin's check project names what each reading recovers, and the plugin recovers it\" in node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","mode":"batched","state":"structural defect","enforces":["every bundled language plugin's check project names what each reading recovers, and the plugin recovers it"]}]} +{"at":"2026-10-26T21:58:02.789Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29014,"load":{"average":3.69,"cores":14},"batch":{"ms":28696},"invariants":[{"component":"src/lifecycle","name":"a tool hook over the latency budget says so","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28696,"reason":"1 test under \"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":65,"mode":"batched","state":"invariant","enforces":["a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it"]},{"component":"src/plugins","name":"every bundled language plugin gives every reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28696,"reason":"7 tests under \"every bundled language plugin's check project names what each reading recovers, and the plugin recovers it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":17706,"mode":"batched","state":"invariant","enforces":["every bundled language plugin's check project names what each reading recovers, and the plugin recovers it"]},{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28696,"reason":"5 tests under \"every bundled language plugin passes every duty of its own plugin check\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":11803,"mode":"batched","state":"requirement","enforces":["every bundled language plugin passes every duty of its own plugin check"]}]} +{"at":"2026-10-26T21:59:24.678Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":81600,"load":{"average":3.83,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a tool hook over the latency budget says so","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22990,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it"]},{"component":"src/plugins","name":"every bundled language plugin gives every reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29216,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every bundled language plugin'\\''s check project names what each reading recovers, and the plugin recovers it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["every bundled language plugin's check project names what each reading recovers, and the plugin recovers it"]},{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":29363,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every bundled language plugin passes every duty of its own plugin check' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["every bundled language plugin passes every duty of its own plugin check"]}]} +{"at":"2026-10-26T22:00:05.878Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29633,"load":{"average":3.76,"cores":14},"batch":{"ms":29328},"invariants":[{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":29328,"reason":"2 of 5 tests under \"every bundled language plugin passes every duty of its own plugin check\" failed: every bundled language plugin's check project names what each reading recovers, and the plugin recovers it every bundled language plugin passes every duty of its own plugin check python; every bundled language plugin's check project names what each reading recovers, and the plugin recovers it every bundled language plugin passes every duty of its own plugin check","testMs":12012,"mode":"batched","state":"requirement","enforces":["every bundled language plugin passes every duty of its own plugin check"]}]} +{"kind":"refutation","at":"2026-10-26T22:00:06.177Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","broke":"left one of Python's check project's references a line off from the file it names (render.py:12 for :13), as df-11317061 left them after the file changed (plugins/python/check.json)","verdict":"fail","reason":"2 of 5 tests under \"every bundled language plugin passes every duty of its own plugin check\" failed: every bundled language plugin's check project names what each reading recovers, and the plugin recovers it every bundled language plugin passes every duty of its own plugin check python; every bundled language plugin's check project names what each reading recovers, and the plugin recovers it every bundled language plugin passes every duty of its own plugin check","commit":"870296d","dirty":true} +{"at":"2026-10-26T22:00:42.588Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29893,"load":{"average":4.33,"cores":14},"batch":{"ms":29563},"invariants":[{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29563,"reason":"5 tests under \"every bundled language plugin passes every duty of its own plugin check\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":12001,"mode":"batched","state":"invariant","enforces":["every bundled language plugin passes every duty of its own plugin check"]}]} +{"at":"2026-10-26T22:01:12.443Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29559,"load":{"average":4.27,"cores":14},"invariants":[{"component":"src/plugins","name":"every bundled language plugin passes its own plugin check","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29526,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every bundled language plugin passes every duty of its own plugin check' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["every bundled language plugin passes every duty of its own plugin check"]}]} +{"at":"2026-10-26T22:02:47.377Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23175,"load":{"average":3.43,"cores":14},"batch":{"ms":22862},"invariants":[{"component":"src/plugins","name":"a shape a project writes and no check project holds is named","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22862,"reason":"1 test under \"plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":30,"mode":"batched","state":"requirement","enforces":["plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds"]}]} +{"at":"2026-10-26T22:03:10.902Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23231,"load":{"average":4.83,"cores":14},"invariants":[{"component":"src/plugins","name":"a shape a project writes and no check project holds is named","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23201,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin shapes counts each shape of import the project writes beside its plugin'\\''s check projects, and names each the project writes that no check project holds' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds"]}]} +{"at":"2026-10-26T22:03:35.103Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23580,"load":{"average":4.83,"cores":14},"batch":{"ms":23266},"invariants":[{"component":"src/plugins","name":"a shape a project writes and no check project holds is named","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23266,"reason":"1 of 1 tests under \"plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds\" failed: plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds","testMs":30,"mode":"batched","state":"requirement","enforces":["plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds"]}]} +{"kind":"refutation","at":"2026-10-26T22:03:35.395Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a shape a project writes and no check project holds is named","form":"totality oracle","broke":"made the reading name a shape untested only where the check projects hold fewer than none, so none is ever named (src/plugins/shapes.ts shapesText)","verdict":"fail","reason":"1 of 1 tests under \"plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds\" failed: plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds","commit":"870296d","dirty":true} +{"at":"2026-10-26T22:03:59.655Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23728,"load":{"average":4.77,"cores":14},"batch":{"ms":23404},"invariants":[{"component":"src/plugins","name":"a shape a project writes and no check project holds is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23404,"reason":"1 test under \"plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":29,"mode":"batched","state":"invariant","enforces":["plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds"]}]} +{"at":"2026-10-26T22:04:23.491Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23535,"load":{"average":4.51,"cores":14},"invariants":[{"component":"src/plugins","name":"a shape a project writes and no check project holds is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23502,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin shapes counts each shape of import the project writes beside its plugin'\\''s check projects, and names each the project writes that no check project holds' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.4ac455b7.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.4ac455b7.jsonl new file mode 100644 index 00000000..ef2c2fcf --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.4ac455b7.jsonl @@ -0,0 +1,6 @@ +{"at":"2026-10-27T03:16:43.688Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c8c65e3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23385,"load":{"average":6.78,"cores":14},"batch":{"ms":23065},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23065,"reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it","testMs":7,"mode":"batched","state":"requirement","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]}]} +{"kind":"refutation","at":"2026-10-27T03:16:43.986Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","broke":"put back the stock tree-sitter-typescript 0.23.2 parsers, unpatched (plugins/typescript/tree-sitter-typescript.wasm and tree-sitter-tsx.wasm)","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it","commit":"c8c65e3","dirty":true} +{"at":"2026-10-27T03:17:28.829Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c8c65e3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23735,"load":{"average":5.31,"cores":14},"batch":{"ms":23429},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23429,"reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it","testMs":106,"mode":"batched","state":"requirement","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]}]} +{"kind":"refutation","at":"2026-10-27T03:17:29.122Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","broke":"built the parsers with a semicolon scanner that ends every line before in, so key\\n in record no longer continues (common/scanner.h in grammars/tree-sitter-typescript/coherence.patch)","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it","commit":"c8c65e3","dirty":true} +{"at":"2026-10-27T03:18:06.192Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c8c65e3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24114,"load":{"average":4.24,"cores":14},"batch":{"ms":23610},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23610,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":103,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]}]} +{"at":"2026-10-27T03:18:30.392Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c8c65e3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23903,"load":{"average":5.05,"cores":14},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23871,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.4c25ed1a.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.4c25ed1a.jsonl new file mode 100644 index 00000000..88d979e0 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.4c25ed1a.jsonl @@ -0,0 +1,6 @@ +{"at":"2026-10-26T22:18:51.953Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23738,"load":{"average":3.8,"cores":14},"batch":{"ms":23391},"invariants":[{"component":"src/plugins","name":"every language plugin reads the reference project alike","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23391,"reason":"1 test under \"plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":53,"mode":"batched","state":"requirement","enforces":["plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way"]}]} +{"at":"2026-10-26T22:19:15.872Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23619,"load":{"average":4.47,"cores":14},"invariants":[{"component":"src/plugins","name":"every language plugin reads the reference project alike","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23588,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin compare lays every language plugin'\\''s reading of the reference project side by side, and names a plugin that reads a relation another way' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way"]}]} +{"at":"2026-10-26T22:19:40.634Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24140,"load":{"average":4.27,"cores":14},"batch":{"ms":23820},"invariants":[{"component":"src/plugins","name":"every language plugin reads the reference project alike","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23820,"reason":"1 of 1 tests under \"plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way\" failed: plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way","testMs":48,"mode":"batched","state":"requirement","enforces":["plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way"]}]} +{"kind":"refutation","at":"2026-10-26T22:19:40.931Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"every language plugin reads the reference project alike","form":"totality oracle","broke":"counted a reference relation held when the reading found no import from that file at all (src/plugins/check.ts referenceRelations)","verdict":"fail","reason":"1 of 1 tests under \"plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way\" failed: plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way","commit":"870296d","dirty":true} +{"at":"2026-10-26T22:20:05.905Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24381,"load":{"average":3.81,"cores":14},"batch":{"ms":24055},"invariants":[{"component":"src/plugins","name":"every language plugin reads the reference project alike","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24055,"reason":"1 test under \"plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":52,"mode":"batched","state":"invariant","enforces":["plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way"]}]} +{"at":"2026-10-26T22:20:30.343Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"870296d","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24149,"load":{"average":2.76,"cores":14},"invariants":[{"component":"src/plugins","name":"every language plugin reads the reference project alike","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24118,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin compare lays every language plugin'\\''s reading of the reference project side by side, and names a plugin that reads a relation another way' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.502b1323.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.502b1323.jsonl new file mode 100644 index 00000000..ffcf8113 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.502b1323.jsonl @@ -0,0 +1,8 @@ +{"at":"2026-10-26T23:23:14.747Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c3097c2","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24360,"load":{"average":14.57,"cores":14},"batch":{"ms":24016},"invariants":[{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24016,"reason":"1 test under \"a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":127,"mode":"batched","state":"requirement","enforces":["a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files"]}]} +{"at":"2026-10-26T23:23:39.001Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c3097c2","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23944,"load":{"average":9.3,"cores":14},"invariants":[{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23911,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a registry'\\''s leaves share one parse store at the repository'\\''s top: a warm-up of one leaf keeps what another leaf'\\''s read, and pre-reads the top'\\''s files' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files"]}]} +{"at":"2026-10-26T23:24:03.879Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c3097c2","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24237,"load":{"average":9.3,"cores":14},"batch":{"ms":23918},"invariants":[{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23918,"reason":"1 of 1 tests under \"a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files\" failed: a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files","testMs":92,"mode":"batched","state":"requirement","enforces":["a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files"]}]} +{"kind":"refutation","at":"2026-10-26T23:24:04.192Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","broke":"kept each project's parses at its own root, as before (src/plugins/languages.ts storeRootOf)","verdict":"fail","reason":"1 of 1 tests under \"a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files\" failed: a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files","commit":"c3097c2","dirty":true} +{"at":"2026-10-26T23:24:29.042Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c3097c2","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24142,"load":{"average":8.02,"cores":14},"batch":{"ms":23823},"invariants":[{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23823,"reason":"1 of 1 tests under \"a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files\" failed: a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files","testMs":128,"mode":"batched","state":"requirement","enforces":["a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files"]}]} +{"kind":"refutation","at":"2026-10-26T23:24:29.352Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","broke":"made a warm-up's rewrite keep only what that pass read (src/plugins/syntax-trees.ts rewrite)","verdict":"fail","reason":"1 of 1 tests under \"a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files\" failed: a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files","commit":"c3097c2","dirty":true} +{"at":"2026-10-26T23:24:54.178Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c3097c2","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24187,"load":{"average":8.24,"cores":14},"batch":{"ms":23830},"invariants":[{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23830,"reason":"1 test under \"a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":130,"mode":"batched","state":"invariant","enforces":["a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files"]}]} +{"at":"2026-10-26T23:25:18.539Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c3097c2","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24062,"load":{"average":5.29,"cores":14},"invariants":[{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24030,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a registry'\\''s leaves share one parse store at the repository'\\''s top: a warm-up of one leaf keeps what another leaf'\\''s read, and pre-reads the top'\\''s files' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.543c9fd6.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.543c9fd6.jsonl new file mode 100644 index 00000000..4cd8cd1b --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.543c9fd6.jsonl @@ -0,0 +1,2 @@ +{"at":"2026-10-27T20:17:34.914Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":39327,"load":{"average":9.96,"cores":14},"batch":{"ms":38077},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":301,"mode":"batched","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":622,"mode":"batched","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":11765,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"an empty slot is said as not read","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a plugin that names no parser is named not read by mass, with why, never measured as a project of no code\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":21,"mode":"batched","state":"invariant","enforces":["a plugin that names no parser is named not read by mass, with why, never measured as a project of no code"]},{"component":"src/plugins","name":"a plugin gives each answer in one slot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"no bundled plugin gives one answer in two slots: no two of its slots' functions are one function or two spelled alike\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":14,"mode":"batched","state":"invariant","enforces":["no bundled plugin gives one answer in two slots: no two of its slots' functions are one function or two spelled alike"]},{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":21,"mode":"batched","state":"invariant","enforces":["a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through"]},{"component":"src/plugins","name":"an ejected copy is told to eject again","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch"]},{"component":"src/plugins","name":"an interfaces table states facts alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":25,"mode":"batched","state":"invariant","enforces":["an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser"]},{"component":"src/plugins","name":"a parser reads a statement whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":6,"mode":"batched","state":"invariant","enforces":["the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment"]},{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":125,"mode":"batched","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":67,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":2,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]},{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":347,"mode":"batched","state":"invariant","enforces":["a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":594,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":101,"mode":"batched","state":"invariant","enforces":["plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":257,"mode":"batched","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":458,"mode":"batched","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":276,"mode":"batched","state":"invariant","enforces":["a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":84,"symbol":"KeptReader","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":204,"symbol":"treeReaderOf","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":256,"symbol":"warmParses","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":276,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":439,"symbol":"readerOver","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":546,"symbol":"ParseStore.stores","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":558,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":559,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":560,"symbol":"ParseStore.of.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":567,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":567,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":569,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":607,"symbol":"ParseStore.discard","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":623,"symbol":"ParseStore.sweep.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":656,"symbol":"ParseStore.writeAudit.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":669,"symbol":"ParseStore.audits.parses","class":"inside","of":"protected","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":473,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:690 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["ParseStore in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":0,"mode":"batched","state":"invariant","enforces":["syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":311,"mode":"batched","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]},{"component":"src/plugins","name":"two warm-ups at once need no lock","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":187,"mode":"batched","state":"invariant","enforces":["two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it"]},{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":108,"mode":"batched","state":"invariant","enforces":["a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept"]},{"component":"src/spec","name":"a practice fires on a defect's class","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":63,"mode":"batched","state":"invariant","enforces":["a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":2155,"mode":"batched","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":38077,"reason":"1 test under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<26 names> src/**/*.test.ts src/*.e2e.ts","testMs":969,"mode":"batched","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"at":"2026-10-27T20:28:14.720Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":639476,"load":{"average":5.59,"cores":14},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24876,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24991,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29958,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23971,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='Coherence'\\''s folders in the user'\\''s configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/\\.config and ~/\\.cache under a home that is absolute, HOME'\\''s, the account'\\''s or Node'\\''s, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"an empty slot is said as not read","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23868,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a plugin that names no parser is named not read by mass, with why, never measured as a project of no code' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a plugin that names no parser is named not read by mass, with why, never measured as a project of no code"]},{"component":"src/plugins","name":"a plugin gives each answer in one slot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24016,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='no bundled plugin gives one answer in two slots: no two of its slots'\\'' functions are one function or two spelled alike' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["no bundled plugin gives one answer in two slots: no two of its slots' functions are one function or two spelled alike"]},{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24193,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a manifest that fills a hand-written reader slot \\(source, declares, topLevel or kept\\) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through"]},{"component":"src/plugins","name":"an ejected copy is told to eject again","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24052,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a copy ejected from Coherence 1\\.10\\.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch"]},{"component":"src/plugins","name":"an interfaces table states facts alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23884,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='an interfaces table states its language'\\''s facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser"]},{"component":"src/plugins","name":"a parser reads a statement whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23859,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads Python'\\''s imports and declarations whole: across lines, in blocks, never inside a string or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment"]},{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24004,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads TypeScript'\\''s imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23922,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23928,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers\\.sha256 records, which the build phase checks its build against' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]},{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24183,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a project'\\''s parses are kept between processes, in the user'\\''s cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24701,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24233,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration'\\''s kind from what surrounds it, so its line read alone says otherwise, named by file and name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24378,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store lives outside every project and is used only where the user'\\''s cache is the user'\\''s alone: a project'\\''s own \\.coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24440,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is read only where it is the user'\\''s alone: a store folder, or a kept parse'\\''s folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24648,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24868,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='syntax-trees\\.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24572,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint'\\''s folder; one read since is kept' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]},{"component":"src/plugins","name":"two warm-ups at once need no lock","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24690,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='two warm-ups of one project at once both read every text, need no lock, and keep each text'\\''s parse once, whole and as a fresh parse reads it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it"]},{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24339,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a registry'\\''s leaves and its top share the user'\\''s one parse store: a warm-up of one leaf pre-reads the leaf and the top'\\''s files, and a warm-up of another reads what the first kept' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept"]},{"component":"src/spec","name":"a practice fires on a defect's class","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24159,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25866,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human'\\''s acknowledgement answers it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24840,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.58c8ce95.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.58c8ce95.jsonl new file mode 100644 index 00000000..aa89a4d7 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.58c8ce95.jsonl @@ -0,0 +1,13 @@ +{"at":"2026-10-27T04:13:19.948Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"43198aa","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":25844,"load":{"average":3.23,"cores":14},"batch":{"ms":24281},"invariants":[{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":272,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":553,"symbol":"ParseStore.of.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":565,"symbol":"ParseStore.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":571,"symbol":"ParseStore.constructor","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":772,"symbol":"StoreFolder.constructor","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":777,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":779,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":783,"symbol":"StoreFolder.all","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":785,"symbol":"StoreFolder.all","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":786,"symbol":"StoreFolder.all","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":786,"symbol":"StoreFolder.all.map() callback","class":"inside","of":"chokepoint","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":704,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:748 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"requirement","enforces":["StoreFolder in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24281,"reason":"1 test under \"the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":21,"mode":"batched","state":"requirement","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"chokepoint","grade":"broken","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":0,"reason":"chokepoint no symbol named rewrite in a file ending with src/plugins/syntax-trees.ts; the protected thing stands with no chokepoint","state":"requirement","enforces":["rewrite in src/plugins/syntax-trees.ts"]}]} +{"at":"2026-10-27T04:23:25.675Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"43198aa","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24125,"load":{"average":3.64,"cores":14},"batch":{"ms":23753},"invariants":[{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23753,"reason":"1 of 1 tests under \"the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder\" failed: the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder","testMs":21,"mode":"batched","state":"requirement","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]}]} +{"kind":"refutation","at":"2026-10-27T04:23:25.972Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","broke":"gave the lock back with a direct rmSync of the store's file, past StoreFolder (ParseStore.unlock in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder\" failed: the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder","commit":"43198aa","dirty":true} +{"at":"2026-10-27T04:23:55.305Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"43198aa","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24553,"load":{"average":3.82,"cores":14},"batch":{"ms":24229},"invariants":[{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24229,"reason":"1 of 1 tests under \"a store's generation is made only by ParseStore's rewrite, an append writes only the log, and a discard leaves no store file: no write but a rewrite or a discard changes the generation a process loaded\" failed: a store's generation is made only by ParseStore's rewrite, an append writes only the log, and a discard leaves no store file: no write but a rewrite or a discard changes the generation a process loaded","testMs":19,"mode":"batched","state":"requirement","enforces":["a store's generation is made only by ParseStore's rewrite, an append writes only the log, and a discard leaves no store file: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"kind":"refutation","at":"2026-10-27T04:23:55.705Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","broke":"made a new generation at each append (ParseStore.flush in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a store's generation is made only by ParseStore's rewrite, an append writes only the log, and a discard leaves no store file: no write but a rewrite or a discard changes the generation a process loaded\" failed: a store's generation is made only by ParseStore's rewrite, an append writes only the log, and a discard leaves no store file: no write but a rewrite or a discard changes the generation a process loaded","commit":"43198aa","dirty":true} +{"at":"2026-10-27T04:24:25.503Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"43198aa","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24929,"load":{"average":3.75,"cores":14},"batch":{"ms":24593},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24593,"reason":"1 of 1 tests under \"a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":527,"mode":"batched","state":"requirement","enforces":["a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T04:24:25.779Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"dropped the check that origin/main is an ancestor of HEAD (prereleaseProblems in src/lifecycle/prerelease.ts)","verdict":"fail","reason":"1 of 1 tests under \"a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"43198aa","dirty":true} +{"at":"2026-10-27T04:24:52.391Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"43198aa","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25268,"load":{"average":3.78,"cores":14},"batch":{"ms":24948},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24948,"reason":"1 of 1 tests under \"a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":851,"mode":"batched","state":"requirement","enforces":["a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T04:24:52.690Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"held only the package's own version, not the bundled manifests' (prereleaseProblems in src/lifecycle/prerelease.ts)","verdict":"fail","reason":"1 of 1 tests under \"a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"43198aa","dirty":true} +{"at":"2026-10-27T04:25:18.776Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"43198aa","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24464,"load":{"average":3.7,"cores":14},"batch":{"ms":24135},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24135,"reason":"1 of 1 tests under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against\" failed: the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against","testMs":2,"mode":"batched","state":"requirement","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against"]}]} +{"kind":"refutation","at":"2026-10-27T04:25:19.061Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","broke":"put e8f802e's parsers back, which build.sh no longer builds (plugins/typescript/*.wasm)","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against\" failed: the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against","commit":"43198aa","dirty":true} +{"at":"2026-10-27T04:26:08.214Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"43198aa","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":30148,"load":{"average":4.28,"cores":14},"batch":{"ms":28692},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":1635,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":63,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":425,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":87,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":5,"mode":"batched","state":"invariant","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":399,"mode":"batched","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":1747,"mode":"batched","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sitesRef":{"hash":"sha256:76825b79c976cb0586c7549bcdc64c663e2c49934595cfe27f30821b1971e965","at":"2026-10-27T04:13:19.948Z"},"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":644,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:748 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["StoreFolder in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":12,"mode":"batched","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28692,"reason":"1 test under \"a store's generation is made only by ParseStore's rewrite, an append writes only the log, and a discard leaves no store file: no write but a rewrite or a discard changes the generation a process loaded\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<10 names> src/**/*.test.ts src/*.e2e.ts","testMs":9,"mode":"batched","state":"invariant","enforces":["a store's generation is made only by ParseStore's rewrite, an append writes only the log, and a discard leaves no store file: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T04:30:09.597Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"43198aa","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":241025,"load":{"average":5.39,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24583,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a pushed, committed HEAD that holds origin'\\''s main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a pushed, committed HEAD that holds origin's main, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22720,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22438,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build\\.sh builds: each is byte for byte the digest the script records and checks its build against' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22824,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24202,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24568,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store'\\''s file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24805,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a log line is read only where it signs itself with this machine'\\''s key, a torn line is passed over, and a log that fails more than a torn line'\\''s worth is read no further, so a repository'\\''s log costs a few signatures whatever its size' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26559,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log'\\''s path never holds a process up, and a key file too short to be one is replaced' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24172,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees\\.ts outside StoreFolder reads Coherence'\\''s own files or the machine key, and only StoreFolder spells the store'\\''s folder' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24111,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a store'\\''s generation is made only by ParseStore'\\''s rewrite, an append writes only the log, and a discard leaves no store file: no write but a rewrite or a discard changes the generation a process loaded' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a store's generation is made only by ParseStore's rewrite, an append writes only the log, and a discard leaves no store file: no write but a rewrite or a discard changes the generation a process loaded"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.6c7e016d.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.6c7e016d.jsonl new file mode 100644 index 00000000..d180d68d --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.6c7e016d.jsonl @@ -0,0 +1,6 @@ +{"at":"2026-10-26T20:51:57.658Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"46d80e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22858,"load":{"average":3.26,"cores":14},"batch":{"ms":22548},"invariants":[{"component":"src/economy","name":"an import of a module joins the files that declare what it imports","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22548,"reason":"1 test under \"an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":17,"mode":"batched","state":"requirement","enforces":["an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name"]}]} +{"at":"2026-10-26T20:52:20.653Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"46d80e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22705,"load":{"average":3.58,"cores":14},"invariants":[{"component":"src/economy","name":"an import of a module joins the files that declare what it imports","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22675,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name"]}]} +{"at":"2026-10-26T20:52:54.407Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"46d80e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23137,"load":{"average":5.25,"cores":14},"batch":{"ms":22823},"invariants":[{"component":"src/economy","name":"an import of a module joins the files that declare what it imports","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22823,"reason":"1 of 1 tests under \"an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name\" failed: an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name","testMs":18,"mode":"batched","state":"requirement","enforces":["an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name"]}]} +{"kind":"refutation","at":"2026-10-26T20:52:54.704Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/economy","name":"an import of a module joins the files that declare what it imports","form":"totality oracle","broke":"made an import of a module join the module's first file alone, as Go's and two blind Swift plugins' rules did (src/economy/source.ts importsOf)","verdict":"fail","reason":"1 of 1 tests under \"an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name\" failed: an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name","commit":"46d80e0","dirty":true} +{"at":"2026-10-26T20:53:18.656Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"46d80e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23436,"load":{"average":4.9,"cores":14},"batch":{"ms":23104},"invariants":[{"component":"src/economy","name":"an import of a module joins the files that declare what it imports","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23104,"reason":"1 test under \"an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":17,"mode":"batched","state":"invariant","enforces":["an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name"]}]} +{"at":"2026-10-26T20:53:42.096Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"46d80e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23153,"load":{"average":5.05,"cores":14},"invariants":[{"component":"src/economy","name":"an import of a module joins the files that declare what it imports","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23122,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.6cf977dd.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.6cf977dd.jsonl new file mode 100644 index 00000000..3acea248 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.6cf977dd.jsonl @@ -0,0 +1,2 @@ +{"at":"2026-10-27T22:15:41.516Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e336378","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":14055,"load":{"average":6.25,"cores":14},"invariants":[{"component":"src/adapters","name":"name forms","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"plugins/convex/convex.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/convex/convex.ts","line":128,"symbol":"ConvexAdapter.namesOf.parsed","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/convex/convex.ts","line":161,"symbol":"ConvexAdapter.stageGeneratedApiUse.parsed","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/declared/declared.ts","line":26,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/declared/declared.ts","line":268,"symbol":"DeclaredAdapter.resolve.parsed","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/declared/declared.ts","line":399,"symbol":"DeclaredAdapter.stagedName.parsed","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/go/go.ts","line":37,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/go/go.ts","line":300,"symbol":"GoAdapter.resolve.parsed","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/python/python.ts","line":78,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/python/python.ts","line":815,"symbol":"PythonAdapter.resolve.parsed","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":36,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/rust/rust.ts","line":596,"symbol":"RustAdapter.resolve.parsed","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":33,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/typescript/typescript.ts","line":491,"symbol":"TypeScriptAdapter.resolve.parsed","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/adapters/adapter.test.ts","line":8,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/adapter.test.ts","line":14,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":15,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":16,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":17,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":18,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":19,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":21,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":22,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":23,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":24,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":25,"symbol":"test(\"a spec value reads as a bare symbol, a symbol in a file, a module path, or prose\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":73,"symbol":"test(\"a spec value with a trailing slash reads as a package module, and pytest file names are test paths\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":74,"symbol":"test(\"a spec value with a trailing slash reads as a package module, and pytest file names are test paths\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.ts","line":295,"symbol":"parseName","class":"inside","of":"protected","test":false},{"file":"src/economy/mass.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/economy/mass.ts","line":116,"symbol":"reachOf.parsed","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/run.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/enforcement/run.ts","line":234,"symbol":"enforcementLanguages.named.flatMap() callback.form","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/api.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"re-export"}],"testReferences":0,"files":["plugins/convex/convex.ts","plugins/declared/declared.ts","plugins/go/go.ts","plugins/python/python.ts","plugins/rust/rust.ts","plugins/typescript/typescript.ts","src/adapters/adapter.test.ts","src/adapters/adapter.ts","src/economy/mass.ts","src/enforcement/run.ts","src/plugins/api.ts"],"latency":2062,"reason":"IDENTIFIER in adapter.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/adapters/adapter.ts:277 declares IDENTIFIER without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["parseName"]},{"component":"src/adapters","name":"ladder is adapter-defined","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"plugins/typescript/index.ts","line":8,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/typescript/index.ts","line":11,"symbol":"typescript.adapter","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":262,"symbol":"TypeScriptAdapter.ladder","class":"inside","of":"protected","test":false},{"file":"src/adapters/adapter.test.ts","line":11,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/adapter.test.ts","line":56,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":63,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":68,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/listing.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/listing.test.ts","line":53,"symbol":"test(\"the TypeScript adapter reads the project's files once per forget: a file created after the listing is found only after a forget\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/listing.test.ts","line":96,"symbol":"test(\"a cold server resolves a name the project declares even when the first source file of the walk lies outside the TypeScript project\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/listing.test.ts","line":116,"symbol":"test(\"the TypeScript adapter spawns git a fixed number of times between forgets, whatever the number of names asked\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/project-files.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/project-files.test.ts","line":72,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/project-files.test.ts","line":94,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/project-files.test.ts","line":160,"symbol":"test(\"a folder the config names as a plugin is not the project's source: its files are walked by nothing and graded by nothing, its declarations shadow not...) callback.own","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/project-files.test.ts","line":180,"symbol":"test(\"a folder the config names as a plugin is not the project's source: its files are walked by nothing and graded by nothing, its declarations shadow not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/economy/economy.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/economy/economy.test.ts","line":77,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/economy/economy.test.ts","line":95,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":120,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":139,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":508,"symbol":"test(\"the check reads the current disk text after a forget, with the instrument's watcher blind to the file: a loop of edit-then-check yields zero wrong ve...) callback.fresh","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":538,"symbol":"test(\"every site the language server reports is a reference: a bypass beneath a semicolon-less bare import is a bypass, and an import outside the chokepoin...) callback.fresh","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":566,"symbol":"ruledTree","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":578,"symbol":"ruledTree.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":790,"symbol":"test(\"the automatic refutation is vacuous unless the check's own classification calls the synthetic site a bypass\") callback.fresh","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/from.test.ts","line":64,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":82,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/javascript.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/javascript.test.ts","line":64,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/javascript.test.ts","line":80,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/javascript.test.ts","line":152,"symbol":"test(\"a TypeScript project that tracks its compiled output: the seed, the resolution and the cold-start text search stay on the TypeScript source\") callback.fresh","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/server.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/server.test.ts","line":84,"symbol":"test(\"a served refutation stages what the adapter in process stages, the exempt folder and the occasion carried\") callback.local","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":16,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook-speed.test.ts","line":138,"symbol":"test(\"an edit says which chokepoint invariants it could not check, and stays silent only for a value the spec writes as prose\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":158,"symbol":"test(\"a protected name in a file of none of the project's languages starts no check at the edit; the same name in its code does\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/monorepo.test.ts","line":242,"symbol":"test(\"a chokepoint verdict over a nested project says its reference search covered that folder alone\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":292,"symbol":"underHorizon.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":41,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":598,"symbol":"test(\"an edit's chokepoint check never goes silent because a cache cannot be used\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":21,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/observation/observation.test.ts","line":100,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":137,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/component-interfaces.test.ts","line":26,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/component-interfaces.test.ts","line":218,"symbol":"test(\"the prefilter never hides a cross-component reference\") callback.tsReadings","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":4,"files":["plugins/typescript/index.ts","plugins/typescript/typescript.ts","src/adapters/adapter.test.ts","src/adapters/listing.test.ts","src/adapters/project-files.test.ts","src/economy/economy.test.ts","src/enforcement/enforcement.test.ts","src/enforcement/from.test.ts","src/enforcement/javascript.test.ts","src/enforcement/server.test.ts","src/lifecycle/hook-speed.test.ts","src/lifecycle/monorepo.test.ts","src/lifecycle/work-meter.test.ts","src/observation/observation.test.ts","src/readings/scope/component-interfaces.test.ts"],"latency":323,"reason":"TYPESCRIPT_LADDER is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (plugins/typescript/typescript.ts:94 reads \"export const TYPESCRIPT_LADDER: Ladder = manifest.ladder as \"); every reference in the project is inside the chokepoint; 4 test references","state":"invariant","enforces":["TypeScriptAdapter"]},{"component":"src/adapters","name":"Python rungs verified","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"plugins/python/index.ts","line":9,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/python/index.ts","line":13,"symbol":"python.adapter","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/python/python.ts","line":529,"symbol":"PythonAdapter.ladder","class":"inside","of":"protected","test":false},{"file":"src/adapters/adapter.test.ts","line":9,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/adapter.test.ts","line":9,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/adapter.test.ts","line":61,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":62,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":64,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":65,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":66,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":67,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":69,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":69,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/listing.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/listing.test.ts","line":71,"symbol":"test(\"the Python adapter reads the project's files once per forget: a module created after the listing is found only after a forget\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python-from.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/python-from.test.ts","line":18,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python-from.test.ts","line":36,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":26,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/python.test.ts","line":127,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":154,"symbol":"definitionOf","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":226,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":245,"symbol":"test(\"Python waits for whole-workspace enumeration before bare-name resolution and references, and finds references outside the component\") callback.controlled","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":492,"symbol":"test(\"Python, ruling d-7abd1ba8: an import at the top of the chokepoint's module is inside; the same import elsewhere, an __all__ re-export, a bare star im...) callback.fresh","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":538,"symbol":"test(\"a bounded Python server gets the heap its reading asks for; an unbounded one keeps Node's default\") callback.adapters","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":538,"symbol":"test(\"a bounded Python server gets the heap its reading asks for; an unbounded one keeps Node's default\") callback.adapters","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/tach.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/tach.test.ts","line":58,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/tach.test.ts","line":101,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/tach.test.ts","line":228,"symbol":"test(\"an edit spawns tach only when a file it wrote is a Python file inside a tach module, and checks only those files\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":255,"symbol":"test(\"a nested Python project's imports written from the repository top resolve, so a bypass inside the project through one is found\") callback.PythonAdapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":291,"symbol":"underHorizon.PythonAdapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":22,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/observation/observation.test.ts","line":407,"symbol":"test(\"the Python fixture observed through coverage.py dynamic contexts, one context per test\") callback.pyAdapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/component-interfaces.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/component-interfaces.test.ts","line":225,"symbol":"test(\"the prefilter never hides a cross-component reference\") callback.pyReadings","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":8,"files":["plugins/python/index.ts","plugins/python/python.ts","src/adapters/adapter.test.ts","src/adapters/listing.test.ts","src/adapters/python-from.test.ts","src/adapters/python.test.ts","src/adapters/tach.test.ts","src/lifecycle/monorepo.test.ts","src/observation/observation.test.ts","src/readings/scope/component-interfaces.test.ts"],"latency":264,"reason":"PYTHON_LADDER is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (plugins/python/python.ts:129 reads \"export const PYTHON_LADDER: Ladder = manifest.ladder as Ladd\"); every reference in the project is inside the chokepoint; 8 test references","state":"invariant","enforces":["PythonAdapter"]},{"component":"src/adapters","name":"Rust rungs verified","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"plugins/rust/index.ts","line":8,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/rust/index.ts","line":11,"symbol":"rust.adapter","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":298,"symbol":"RustAdapter.ladder","class":"inside","of":"protected","test":false},{"file":"src/adapters/adapter.test.ts","line":10,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/adapter.test.ts","line":57,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":58,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":59,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/adapter.test.ts","line":60,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":111,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":120,"symbol":"definitionOf","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":151,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":383,"symbol":"test(\"Rust waits for rust-analyzer's quiescent status before resolution, references and refutation\") callback.controlled","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":408,"symbol":"test(\"the Rust ladder names rustc for the top rung and Coherence's check below it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":408,"symbol":"test(\"the Rust ladder names rustc for the top rung and Coherence's check below it\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/rust.test.ts","line":409,"symbol":"test(\"the Rust ladder names rustc for the top rung and Coherence's check below it\") callback","class":"test","of":"protected","test":true},{"file":"src/adapters/rust.test.ts","line":410,"symbol":"test(\"the Rust ladder names rustc for the top rung and Coherence's check below it\") callback","class":"test","of":"protected","test":true}],"testReferences":9,"files":["plugins/rust/index.ts","plugins/rust/rust.ts","src/adapters/adapter.test.ts","src/adapters/rust.test.ts"],"latency":251,"reason":"RUST_LADDER is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (plugins/rust/rust.ts:89 reads \"export const RUST_LADDER: Ladder = manifest.ladder as Ladder\"); every reference in the project is inside the chokepoint; 9 test references","state":"invariant","enforces":["RustAdapter"]},{"component":"src/adapters","name":"rust-analyzer located or a reason","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"plugins/rust/index.ts","line":8,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/rust/index.ts","line":11,"symbol":"rust.adapter","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":71,"symbol":"RustClientFactory","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":93,"symbol":"locateServer","class":"inside","of":"protected","test":false},{"file":"plugins/rust/rust.ts","line":298,"symbol":"RustAdapter.ladder","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":300,"symbol":"RustAdapter.clientFactory","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":301,"symbol":"RustAdapter.client","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":327,"symbol":"RustAdapter.constructor","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":358,"symbol":"RustAdapter.start.server","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":360,"symbol":"RustAdapter.start.reason","class":"inside","of":"protected","test":false},{"file":"plugins/rust/rust.ts","line":400,"symbol":"RustAdapter.start.reason","class":"inside","of":"protected","test":false},{"file":"plugins/rust/rust.ts","line":404,"symbol":"RustAdapter.live","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":421,"symbol":"RustAdapter.quiescence..timer.setTimeout() callback","class":"inside","of":"protected","test":false},{"file":"plugins/rust/rust.ts","line":431,"symbol":"RustAdapter.indexed","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":434,"symbol":"RustAdapter.indexed","class":"inside","of":"protected","test":false},{"file":"plugins/rust/rust.ts","line":439,"symbol":"RustAdapter.settled","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":535,"symbol":"RustAdapter.headerOf","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":696,"symbol":"RustAdapter.references.form","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":717,"symbol":"RustAdapter.enclosing.marked.some() callback","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":728,"symbol":"RustAdapter.inTestModule.chain.steps.some() callback","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":785,"symbol":"RustAdapter.place.chain.steps.forEach() callback","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":791,"symbol":"RustAdapter.place","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":870,"symbol":"RustAdapter.refusedByCompiler.refusal.find() callback","class":"inside","of":"chokepoint","test":false},{"file":"plugins/rust/rust.ts","line":872,"symbol":"RustAdapter.refusedByCompiler.control.find() callback","class":"inside","of":"chokepoint","test":false},{"file":"src/adapters/adapter.test.ts","line":10,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/adapter.test.ts","line":57,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":58,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":59,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":60,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":111,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":113,"symbol":"serverPresent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":120,"symbol":"definitionOf","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":151,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":180,"symbol":"test(\"rust-analyzer is found, or its absence names each place looked\") callback.real","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":190,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":191,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":192,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":193,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":193,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":193,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":193,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":197,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":198,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":199,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":200,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":201,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":202,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":203,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":205,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":206,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":207,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":208,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":209,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":210,"symbol":"test(\"the header, the use form and the scope are read from the text alone\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":315,"symbol":"ControlledRustClient","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":316,"symbol":"ControlledRustClient.onNotification","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":317,"symbol":"ControlledRustClient.onRequest","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":383,"symbol":"test(\"Rust waits for rust-analyzer's quiescent status before resolution, references and refutation\") callback.controlled","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":408,"symbol":"test(\"the Rust ladder names rustc for the top rung and Coherence's check below it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":408,"symbol":"test(\"the Rust ladder names rustc for the top rung and Coherence's check below it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":409,"symbol":"test(\"the Rust ladder names rustc for the top rung and Coherence's check below it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":410,"symbol":"test(\"the Rust ladder names rustc for the top rung and Coherence's check below it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":0,"files":["plugins/rust/index.ts","plugins/rust/rust.ts","src/adapters/adapter.test.ts","src/adapters/rust.test.ts"],"latency":1083,"reason":"SERVER_BIN in rust.ts is visibility-choked, enforced by the compiler: not visible outside its module (plugins/rust/rust.ts:73 declares SERVER_BIN without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["plugins/rust/rust.ts"]},{"component":"src/adapters","name":"pytest report mapped by name","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/adapters/python.test.ts","line":24,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/python.test.ts","line":400,"symbol":"test(\"pytest's JUnit report reads as the jest shape, and -k names join with or\") callback.report","class":"test","of":"protected","test":true},{"file":"src/enforcement/latency.test.ts","line":11,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/latency.test.ts","line":50,"symbol":"test(\"a run records each test's time as its runner measured it, from a jest-shaped report, JUnit XML, and pytest-json-report\") callback.jest","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/latency.test.ts","line":54,"symbol":"test(\"a run records each test's time as its runner measured it, from a jest-shaped report, JUnit XML, and pytest-json-report\") callback.junit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/latency.test.ts","line":56,"symbol":"test(\"a run records each test's time as its runner measured it, from a jest-shaped report, JUnit XML, and pytest-json-report\") callback.pytest","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/totality.ts","line":189,"symbol":"parseReport","class":"inside","of":"protected","test":false},{"file":"src/enforcement/totality.ts","line":312,"symbol":"runTotalityBatch","class":"chokepoint-reference","of":"chokepoint","test":false}],"testReferences":2,"files":["src/adapters/python.test.ts","src/enforcement/latency.test.ts","src/enforcement/totality.ts"],"latency":227,"reason":"reportFromJunit is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/totality.ts:151 reads \"export function reportFromJunit(xml: string): JsonReport {\"); every reference in the project is inside the chokepoint; 2 test references","state":"invariant","enforces":["parseReport"]},{"component":"src/adapters","name":"server located or a reason","form":"chokepoint","grade":"not chokeable","verdict":"not run","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":37,"reason":"protected thing SERVER_BIN is declared in 2 places; write `SERVER_BIN in ` (plugins/typescript/typescript.ts:57, src/plugins/fixtures/ejected-1.10.1/typescript/typescript.ts:56); the totality oracle form (over + via) is the compromise where structure is unavailable","state":"requirement","enforces":["plugins/typescript/typescript.ts"]},{"component":"src/economy","name":"calibrate label never manual","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/economy/calibrate.ts","line":104,"symbol":"sampleOf.label","class":"inside","of":"protected","test":false},{"file":"src/economy/calibrate.ts","line":139,"symbol":"calibrate","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/economy/economy.test.ts","line":18,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/economy/economy.test.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/economy/economy.test.ts","line":229,"symbol":"test(\"calibrate: the outcome label is automatic; a later defect record labels defect, a later passing run labels clean, nothing later is unknown, and a lab...) callback","class":"test","of":"protected","test":true},{"file":"src/economy/economy.test.ts","line":231,"symbol":"test(\"calibrate: the outcome label is automatic; a later defect record labels defect, a later passing run labels clean, nothing later is unknown, and a lab...) callback","class":"test","of":"protected","test":true},{"file":"src/economy/economy.test.ts","line":235,"symbol":"test(\"calibrate: the outcome label is automatic; a later defect record labels defect, a later passing run labels clean, nothing later is unknown, and a lab...) callback","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":3,"files":["src/economy/calibrate.ts","src/economy/economy.test.ts"],"latency":222,"reason":"labelSnapshot is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/economy/calibrate.ts:76 reads \"export function labelSnapshot(root: string, snapshot: Snapsh\"); every reference in the project is inside the chokepoint; 3 test references","state":"invariant","enforces":["sampleOf"]},{"component":"src/enforcement","name":"run appended never rewritten","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/adapters/declared.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/declared.test.ts","line":167,"symbol":"test(\"a run routes a declared language's chokepoint to its adapter and records which language answered; a mixed project picks it by the files the component...) callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/python.test.ts","line":434,"symbol":"test(\"the totality oracle pass through pytest: every test the bullets name in one invocation, mapped back from the JUnit report\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":445,"symbol":"test(\"the totality oracle pass through pytest: every test the bullets name in one invocation, mapped back from the JUnit report\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":454,"symbol":"test(\"the totality oracle pass through pytest: every test the bullets name in one invocation, mapped back from the JUnit report\") callback.missing","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":517,"symbol":"test(\"a run over the Python fixture records the grade, the enforcer, and the refutation per chokepoint\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/economy/economy.test.ts","line":15,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/economy/economy.test.ts","line":207,"symbol":"test(\"calibrate: the outcome label is automatic; a later defect record labels defect, a later passing run labels clean, nothing later is unknown, and a lab...) callback","class":"test","of":"protected","test":true},{"file":"src/economy/economy.test.ts","line":283,"symbol":"test(\"mass counts reach by chokepoint or totality oracle, and says plainly when a totality oracle's run record does not name the files its test touched\") callback","class":"test","of":"protected","test":true},{"file":"src/economy/economy.test.ts","line":311,"symbol":"test(\"mass: a file in no component and a file in a component that no invariant reaches count as unreached; unreached prints first; deterministic\") callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/cli.ts","line":29,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/enforcement/cli.ts","line":266,"symbol":"runCommand.outcome","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/cli.ts","line":268,"symbol":"runCommand","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/cli.ts","line":419,"symbol":"refuteCommand.outcome","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/enforcement.test.ts","line":26,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":27,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":220,"symbol":"test(\"run sites persist protected references and chokepoint references without turning an unused import into a call\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":307,"symbol":"test(\"the batched totality oracle pass: every test the bullets name in one invocation, mapped back by name; the record says which mode ran\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":313,"symbol":"test(\"the batched totality oracle pass: every test the bullets name in one invocation, mapped back by name; the record says which mode ran\") callback.single","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":337,"symbol":"test(\"a run appends one record, never rewrites; spec --check reads the run; the status view derives the latest verdict and keeps a skipped one dated\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":367,"symbol":"test(\"a run appends one record, never rewrites; spec --check reads the run; the status view derives the latest verdict and keeps a skipped one dated\") callback.second","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":407,"symbol":"test(\"reference-query failures and legacy records never masquerade as confirmed empty sites\") callback.failed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":420,"symbol":"test(\"reference-query failures and legacy records never masquerade as confirmed empty sites\") callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":443,"symbol":"test(\"a run that cannot check an enforcement an earlier run checked exits 1 and names it; the same not run with no earlier check exits 0\") callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":457,"symbol":"test(\"appendRun refuses a session that cannot name a file\") callback.assert.throws() callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":921,"symbol":"test(\"refute runs the bullet's totality oracle with the break staged, requires it to fail, and appends the refutation record\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/from.test.ts","line":144,"symbol":"test(\"the config's chokepointFrom governs a silent bullet, a bullet's own from: overrides it, and the run records and prints which governed\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":159,"symbol":"test(\"the config's chokepointFrom governs a silent bullet, a bullet's own from: overrides it, and the run records and prints which governed\") callback.unset","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":172,"symbol":"test(\"Scope and the agent query show which references governed: the from: line with its exempt count on the enforcement, each exempt site as exempt, and th...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/languages.test.ts","line":215,"symbol":"test(\"each totality oracle's test runs through the setup whose test files hold it, one batched invocation per setup, from the setup's own folder\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":229,"symbol":"test(\"each totality oracle's test runs through the setup whose test files hold it, one batched invocation per setup, from the setup's own folder\") callback.each","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":244,"symbol":"test(\"each chokepoint resolves and grades through its own language's warm server, and a run or an edit reaches only the languages its checks need\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":260,"symbol":"test(\"each chokepoint resolves and grades through its own language's warm server, and a run or an edit reaches only the languages its checks need\") callback.one","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/run-sites.test.ts","line":14,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/enforcement/run-sites.test.ts","line":49,"symbol":"test(\"a run whose sites did not change stores a reference within its own run file that resolves to the same sites; changed sites are stored in full; a refe...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":50,"symbol":"test(\"a run whose sites did not change stores a reference within its own run file that resolves to the same sites; changed sites are stored in full; a refe...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":52,"symbol":"test(\"a run whose sites did not change stores a reference within its own run file that resolves to the same sites; changed sites are stored in full; a refe...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":53,"symbol":"test(\"a run whose sites did not change stores a reference within its own run file that resolves to the same sites; changed sites are stored in full; a refe...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":67,"symbol":"test(\"a run whose sites did not change stores a reference within its own run file that resolves to the same sites; changed sites are stored in full; a refe...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":68,"symbol":"test(\"a run whose sites did not change stores a reference within its own run file that resolves to the same sites; changed sites are stored in full; a refe...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":119,"symbol":"test(\"over this repository's run store, a run written with its unchanged sites by reference reads exactly as one written in full, in fewer bytes, and no li...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":120,"symbol":"test(\"over this repository's run store, a run written with its unchanged sites by reference reads exactly as one written in full, in fewer bytes, and no li...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":140,"symbol":"longSession","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":153,"symbol":"test(\"an append asks its run file's sites shard, never the file: beside ten times the session's runs it reads the same bytes, and a shard that cannot say w...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":172,"symbol":"test(\"an append asks its run file's sites shard, never the file: beside ten times the session's runs it reads the same bytes, and a shard that cannot say w...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":174,"symbol":"test(\"an append asks its run file's sites shard, never the file: beside ten times the session's runs it reads the same bytes, and a shard that cannot say w...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run-sites.test.ts","line":177,"symbol":"test(\"an append asks its run file's sites shard, never the file: beside ten times the session's runs it reads the same bytes, and a shard that cannot say w...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/run.ts","line":27,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/enforcement/run.ts","line":543,"symbol":"performRun.pass.file","class":"inside","of":"protected","test":false},{"file":"src/enforcement/run.ts","line":582,"symbol":"performRun.pass.file","class":"inside","of":"protected","test":false},{"file":"src/enforcement/server.test.ts","line":16,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/server.test.ts","line":132,"symbol":"test(\"the run keeps the instrument alive across the test pass, and a run whose instrument died exits non-zero with the reason\") callback.died","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/server.test.ts","line":145,"symbol":"test(\"the run keeps the instrument alive across the test pass, and a run whose instrument died exits non-zero with the reason\") callback.kept","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":16,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/journal/shards.test.ts","line":95,"symbol":"appendAll","class":"test","of":"protected","test":true},{"file":"src/lifecycle/ci.test.ts","line":16,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/ci.test.ts","line":272,"symbol":"test(\"ci report carries each project's problems, chokepoint verdicts, spec gaps and guard failures as Markdown, and fails only when Coherence did not finis...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/ci.test.ts","line":273,"symbol":"test(\"ci report carries each project's problems, chokepoint verdicts, spec gaps and guard failures as Markdown, and fails only when Coherence did not finis...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/ci.test.ts","line":274,"symbol":"test(\"ci report carries each project's problems, chokepoint verdicts, spec gaps and guard failures as Markdown, and fails only when Coherence did not finis...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/ci.test.ts","line":296,"symbol":"test(\"ci report carries each project's problems, chokepoint verdicts, spec gaps and guard failures as Markdown, and fails only when Coherence did not finis...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/ci.test.ts","line":297,"symbol":"test(\"ci report carries each project's problems, chokepoint verdicts, spec gaps and guard failures as Markdown, and fails only when Coherence did not finis...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/ci.test.ts","line":488,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"a file name git would quote still matches its finding\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/ci.test.ts","line":504,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"ci report --base, or a pull request's base branch on GitHub Actions, reads the files changed since that commit\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/hook.ts","line":79,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":684,"symbol":"checkAtEdit.outcome","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/work-meter.test.ts","line":35,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":504,"symbol":"test(\"in a project of two languages, an edit's check asks the language the last run graded the invariant in, with that run's whole file list\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":630,"symbol":"test(\"the run index answers as the run history does after appends, a replaced file, a torn or stale index, a held lock and a cache that cannot be written, ...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":632,"symbol":"test(\"the run index answers as the run history does after appends, a replaced file, a torn or stale index, a held lock and a cache that cannot be written, ...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":633,"symbol":"test(\"the run index answers as the run history does after appends, a replaced file, a torn or stale index, a held lock and a cache that cannot be written, ...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":657,"symbol":"test(\"the run index answers as the run history does after appends, a replaced file, a torn or stale index, a held lock and a cache that cannot be written, ...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":665,"symbol":"test(\"the run index answers as the run history does after appends, a replaced file, a torn or stale index, a held lock and a cache that cannot be written, ...) callback.assert.doesNotThrow(\"an append never throws after it appended\") callback","class":"test","of":"protected","test":true},{"file":"src/observation/observation.test.ts","line":26,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/observation/observation.test.ts","line":146,"symbol":"observedRun","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":150,"symbol":"observedRun","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":409,"symbol":"test(\"the Python fixture observed through coverage.py dynamic contexts, one context per test\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/check.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/plugins/check.ts","line":700,"symbol":"instrument.chokepoint.guarded(\"chokepoint\") callback.run","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/convex.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/convex.test.ts","line":69,"symbol":"test(\"the Convex plugin grades a Convex project's chokepoint: a function reached through the generated API outside it is a bypass, its refutation stages th...) callback.graded","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/plugins.test.ts","line":107,"symbol":"test(\"a plugin that extends a language answers its chokepoint checks: the adapter is the plugin's, wrapping the core's, and the run entry names the plugin\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":126,"symbol":"test(\"a via form is proved by the plugin that declares it, graded like a test with its evidence label; a form no plugin declares is a spec problem naming t...) callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":207,"symbol":"test(\"a verifier's command must name what it proves, and with a match its exit 0 passes only when its output matches\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/quint.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/quint.test.ts","line":114,"symbol":"test(\"a Quint bullet is proved through the verifier role: graded like a test with its evidence label, the plugin named, a counterexample failing it, [quint...) callback.record.withQuint() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/floor.test.ts","line":17,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/spec/floor.test.ts","line":60,"symbol":"witness","class":"test","of":"protected","test":true},{"file":"src/spec/floor.test.ts","line":133,"symbol":"test(\"an invariant whose latest run could not check it names that cause before the demotion it offers\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/floor.test.ts","line":135,"symbol":"test(\"an invariant whose latest run could not check it names that cause before the demotion it offers\") callback","class":"test","of":"protected","test":true}],"testReferences":43,"files":["src/adapters/declared.test.ts","src/adapters/python.test.ts","src/economy/economy.test.ts","src/enforcement/cli.ts","src/enforcement/enforcement.test.ts","src/enforcement/from.test.ts","src/enforcement/languages.test.ts","src/enforcement/record.ts","src/enforcement/run-sites.test.ts","src/enforcement/run.ts","src/enforcement/server.test.ts","src/journal/shards.test.ts","src/lifecycle/ci.test.ts","src/lifecycle/hook.ts","src/lifecycle/work-meter.test.ts","src/observation/observation.test.ts","src/plugins/check.ts","src/plugins/convex.test.ts","src/plugins/plugins.test.ts","src/plugins/quint.test.ts","src/spec/floor.test.ts"],"latency":245,"reason":"appendRun is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/record.ts:332 reads \"export function appendRun(root: string, record: RunRecord): \"); every reference in the project is inside the chokepoint; 43 test references","state":"invariant","enforces":["performRun"]},{"component":"src/enforcement","name":"automatic refutation","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/adapters/declared-server.test.ts","line":21,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/declared-server.test.ts","line":59,"symbol":"test(\"a declared language over a real language server: the bypass grades broken, the declared refute template is staged unsaved and seen, and a clean choke...) callback.broken","class":"test","of":"protected","test":true},{"file":"src/adapters/declared-server.test.ts","line":67,"symbol":"test(\"a declared language over a real language server: the bypass grades broken, the declared refute template is staged unsaved and seen, and a clean choke...) callback.clean","class":"test","of":"protected","test":true},{"file":"src/adapters/declared.test.ts","line":23,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/declared.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/declared.test.ts","line":132,"symbol":"test(\"a declared language's chokepoint grades broken with its bypass, then reference-choked once the bypass is gone; the refutation stages the config's tem...) callback.broken","class":"test","of":"protected","test":true},{"file":"src/adapters/declared.test.ts","line":147,"symbol":"test(\"a declared language's chokepoint grades broken with its bypass, then reference-choked once the bypass is gone; the refutation stages the config's tem...) callback.clean","class":"test","of":"protected","test":true},{"file":"src/adapters/declared.test.ts","line":155,"symbol":"test(\"a declared language's chokepoint grades broken with its bypass, then reference-choked once the bypass is gone; the refutation stages the config's tem...) callback.unproved","class":"test","of":"protected","test":true},{"file":"src/adapters/declared.test.ts","line":167,"symbol":"test(\"a run routes a declared language's chokepoint to its adapter and records which language answered; a mixed project picks it by the files the component...) callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/declared.test.ts","line":191,"symbol":"test(\"a declared language's server that misses a file's references never passes: a server answering only from open documents is handed every file, and a fi...) callback.missed","class":"test","of":"protected","test":true},{"file":"src/adapters/declared.test.ts","line":198,"symbol":"test(\"a declared language's server that misses a file's references never passes: a server answering only from open documents is handed every file, and a fi...) callback.opened","class":"test","of":"protected","test":true},{"file":"src/adapters/project-files.test.ts","line":20,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/project-files.test.ts","line":118,"symbol":"test(\"only the project's own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass\") callback.result","class":"test","of":"protected","test":true},{"file":"src/adapters/project-files.test.ts","line":131,"symbol":"test(\"only the project's own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass\") callback.foreign","class":"test","of":"protected","test":true},{"file":"src/adapters/project-files.test.ts","line":185,"symbol":"test(\"a folder the config names as a plugin is not the project's source: its files are walked by nothing and graded by nothing, its declarations shadow not...) callback.graded","class":"test","of":"protected","test":true},{"file":"src/adapters/python-from.test.ts","line":13,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/python-from.test.ts","line":46,"symbol":"test(\"Python: a chokepoint from outside the component exempts its own references and still catches a bypass from another component; from anywhere calls bot...) callback.anywhere","class":"test","of":"protected","test":true},{"file":"src/adapters/python-from.test.ts","line":50,"symbol":"test(\"Python: a chokepoint from outside the component exempts its own references and still catches a bypass from another component; from anywhere calls bot...) callback.scoped","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":20,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/python.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/python.test.ts","line":298,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.broken","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":310,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.clean","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":317,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.hidden","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":321,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.inner","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":331,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.innerElsewhere","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":335,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.member","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":341,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.checked","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":344,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.stillPublic","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":350,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.missing","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":354,"symbol":"test(\"Python grades: broken with a bypass; reference-choked when clean, with the convention as evidence; closure-choked for a function-local; checker-choke...) callback.prose","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":367,"symbol":"test(\"a Python module or package resolves, its members are the references' start, and the package's own files are inside it\") callback.result","class":"test","of":"protected","test":true},{"file":"src/adapters/python.test.ts","line":434,"symbol":"test(\"the totality oracle pass through pytest: every test the bullets name in one invocation, mapped back from the JUnit report\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":445,"symbol":"test(\"the totality oracle pass through pytest: every test the bullets name in one invocation, mapped back from the JUnit report\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":454,"symbol":"test(\"the totality oracle pass through pytest: every test the bullets name in one invocation, mapped back from the JUnit report\") callback.missing","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":517,"symbol":"test(\"a run over the Python fixture records the grade, the enforcer, and the refutation per chokepoint\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/rust.test.ts","line":21,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/rust.test.ts","line":217,"symbol":"test(\"Rust grades: visibility-choked short of the crate, reference-choked for pub(crate) and pub, broken with a bypass, a #[cfg(test)] site is a test\") callback.choked","class":"test","of":"protected","test":true},{"file":"src/adapters/rust.test.ts","line":226,"symbol":"test(\"Rust grades: visibility-choked short of the crate, reference-choked for pub(crate) and pub, broken with a bypass, a #[cfg(test)] site is a test\") callback.deep","class":"test","of":"protected","test":true},{"file":"src/adapters/rust.test.ts","line":231,"symbol":"test(\"Rust grades: visibility-choked short of the crate, reference-choked for pub(crate) and pub, broken with a bypass, a #[cfg(test)] site is a test\") callback.broken","class":"test","of":"protected","test":true},{"file":"src/adapters/rust.test.ts","line":238,"symbol":"test(\"Rust grades: visibility-choked short of the crate, reference-choked for pub(crate) and pub, broken with a bypass, a #[cfg(test)] site is a test\") callback.clean","class":"test","of":"protected","test":true},{"file":"src/adapters/tach.test.ts","line":17,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/tach.test.ts","line":148,"symbol":"test(\"a chokepoint tach governs grades checker-choked by tach with the interface as the fact, the module's own use inside; a planted outside import grades ...) callback.clean","class":"test","of":"protected","test":true},{"file":"src/adapters/tach.test.ts","line":158,"symbol":"test(\"a chokepoint tach governs grades checker-choked by tach with the interface as the fact, the module's own use inside; a planted outside import grades ...) callback.broken","class":"test","of":"protected","test":true},{"file":"src/adapters/tach.test.ts","line":171,"symbol":"test(\"a chokepoint tach governs grades checker-choked by tach with the interface as the fact, the module's own use inside; a planted outside import grades ...) callback.without","class":"test","of":"protected","test":true},{"file":"src/adapters/tach.test.ts","line":186,"symbol":"test(\"tach's refusal of an outside import staged in a throwaway copy is the refutation, and the copy is gone with nothing written into the project\") callback.result","class":"test","of":"protected","test":true},{"file":"src/adapters/tach.test.ts","line":201,"symbol":"test(\"without tach installed the tach rung is not available and the grade says why\") callback.result","class":"test","of":"protected","test":true},{"file":"src/adapters/tach.test.ts","line":206,"symbol":"test(\"without tach installed the tach rung is not available and the grade says why\") callback.clean","class":"test","of":"protected","test":true},{"file":"src/enforcement/cli.ts","line":29,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/enforcement/cli.ts","line":266,"symbol":"runCommand.outcome","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/cli.ts","line":268,"symbol":"runCommand","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/cli.ts","line":419,"symbol":"refuteCommand.outcome","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/enforcement.test.ts","line":22,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":27,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":169,"symbol":"test(\"grades: broken with a bypass, reference-choked when clean and exported, visibility-choked when not exported, broken when the chokepoint is missing, n...) callback.broken","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":181,"symbol":"test(\"grades: broken with a bypass, reference-choked when clean and exported, visibility-choked when not exported, broken when the chokepoint is missing, n...) callback.clean","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":187,"symbol":"test(\"grades: broken with a bypass, reference-choked when clean and exported, visibility-choked when not exported, broken when the chokepoint is missing, n...) callback.hidden","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":205,"symbol":"test(\"grades: broken with a bypass, reference-choked when clean and exported, visibility-choked when not exported, broken when the chokepoint is missing, n...) callback.missing","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":210,"symbol":"test(\"grades: broken with a bypass, reference-choked when clean and exported, visibility-choked when not exported, broken when the chokepoint is missing, n...) callback.prose","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":220,"symbol":"test(\"run sites persist protected references and chokepoint references without turning an unused import into a call\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":307,"symbol":"test(\"the batched totality oracle pass: every test the bullets name in one invocation, mapped back by name; the record says which mode ran\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":313,"symbol":"test(\"the batched totality oracle pass: every test the bullets name in one invocation, mapped back by name; the record says which mode ran\") callback.single","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":337,"symbol":"test(\"a run appends one record, never rewrites; spec --check reads the run; the status view derives the latest verdict and keeps a skipped one dated\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":367,"symbol":"test(\"a run appends one record, never rewrites; spec --check reads the run; the status view derives the latest verdict and keeps a skipped one dated\") callback.second","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":407,"symbol":"test(\"reference-query failures and legacy records never masquerade as confirmed empty sites\") callback.failed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":515,"symbol":"test(\"the check reads the current disk text after a forget, with the instrument's watcher blind to the file: a loop of edit-then-check yields zero wrong ve...) callback.result","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":540,"symbol":"test(\"every site the language server reports is a reference: a bypass beneath a semicolon-less bare import is a bypass, and an import outside the chokepoin...) callback.result","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":688,"symbol":"test(\"the automatic refutation stages both synthetic sites — a use in the chokepoint's own module outside its range and a re-export — and is vacuous unless...) callback.result","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":710,"symbol":"test(\"a protected thing the instrument finds no reference to, not even inside the chokepoint, is not run: there was nothing to check\") callback.result","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":757,"symbol":"test(\"a refusal of a staged outside reference holds a chokepoint over no reference, whether the language or a checker refuses it\") callback.result","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":792,"symbol":"test(\"the automatic refutation is vacuous unless the check's own classification calls the synthetic site a bypass\") callback.inTests","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":800,"symbol":"test(\"the automatic refutation is vacuous unless the check's own classification calls the synthetic site a bypass\") callback.ownModule","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":807,"symbol":"test(\"the automatic refutation is vacuous unless the check's own classification calls the synthetic site a bypass\") callback.symbolChokepoint","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":921,"symbol":"test(\"refute runs the bullet's totality oracle with the break staged, requires it to fail, and appends the refutation record\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":20,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/enforcement/from.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/from.test.ts","line":106,"symbol":"test(\"a chokepoint from outside the component exempts its own references and still catches a bypass from another component; from anywhere calls both bypass...) callback.anywhere","class":"test","of":"protected","test":true},{"file":"src/enforcement/from.test.ts","line":113,"symbol":"test(\"a chokepoint from outside the component exempts its own references and still catches a bypass from another component; from anywhere calls both bypass...) callback.scoped","class":"test","of":"protected","test":true},{"file":"src/enforcement/from.test.ts","line":128,"symbol":"test(\"a chokepoint from outside the component exempts its own references and still catches a bypass from another component; from anywhere calls both bypass...) callback.clean","class":"test","of":"protected","test":true},{"file":"src/enforcement/from.test.ts","line":133,"symbol":"test(\"a chokepoint from outside the component exempts its own references and still catches a bypass from another component; from anywhere calls both bypass...) callback.stillBroken","class":"test","of":"protected","test":true},{"file":"src/enforcement/from.test.ts","line":144,"symbol":"test(\"the config's chokepointFrom governs a silent bullet, a bullet's own from: overrides it, and the run records and prints which governed\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":159,"symbol":"test(\"the config's chokepointFrom governs a silent bullet, a bullet's own from: overrides it, and the run records and prints which governed\") callback.unset","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":172,"symbol":"test(\"Scope and the agent query show which references governed: the from: line with its exempt count on the enforcement, each exempt site as exempt, and th...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/javascript.test.ts","line":20,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/enforcement/javascript.test.ts","line":110,"symbol":"test(\"grades on JavaScript: broken with a bypass, then a pass once the bypass is gone; the automatic refutation stages .mjs documents the project can see\") callback.broken","class":"test","of":"protected","test":true},{"file":"src/enforcement/javascript.test.ts","line":122,"symbol":"test(\"grades on JavaScript: broken with a bypass, then a pass once the bypass is gone; the automatic refutation stages .mjs documents the project can see\") callback.clean","class":"test","of":"protected","test":true},{"file":"src/enforcement/javascript.test.ts","line":131,"symbol":"test(\"grades on JavaScript: broken with a bypass, then a pass once the bypass is gone; the automatic refutation stages .mjs documents the project can see\") callback.hidden","class":"test","of":"protected","test":true},{"file":"src/enforcement/languages.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/languages.test.ts","line":215,"symbol":"test(\"each totality oracle's test runs through the setup whose test files hold it, one batched invocation per setup, from the setup's own folder\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":229,"symbol":"test(\"each totality oracle's test runs through the setup whose test files hold it, one batched invocation per setup, from the setup's own folder\") callback.each","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":244,"symbol":"test(\"each chokepoint resolves and grades through its own language's warm server, and a run or an edit reaches only the languages its checks need\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":260,"symbol":"test(\"each chokepoint resolves and grades through its own language's warm server, and a run or an edit reaches only the languages its checks need\") callback.one","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/run.ts","line":25,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/enforcement/run.ts","line":413,"symbol":"performRun.pass","class":"inside","of":"protected","test":false},{"file":"src/enforcement/server.test.ts","line":16,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/server.test.ts","line":132,"symbol":"test(\"the run keeps the instrument alive across the test pass, and a run whose instrument died exits non-zero with the reason\") callback.died","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/server.test.ts","line":145,"symbol":"test(\"the run keeps the instrument alive across the test pass, and a run whose instrument died exits non-zero with the reason\") callback.kept","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.ts","line":79,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":684,"symbol":"checkAtEdit.outcome","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/monorepo.test.ts","line":19,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/monorepo.test.ts","line":244,"symbol":"test(\"a chokepoint verdict over a nested project says its reference search covered that folder alone\") callback.result","class":"test","of":"protected","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":264,"symbol":"test(\"a nested Python project's imports written from the repository top resolve, so a bypass inside the project through one is found\") callback.result","class":"test","of":"protected","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":294,"symbol":"underHorizon.result","class":"test","of":"protected","test":true},{"file":"src/observation/observation.test.ts","line":26,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/observation/observation.test.ts","line":146,"symbol":"observedRun","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":150,"symbol":"observedRun","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":409,"symbol":"test(\"the Python fixture observed through coverage.py dynamic contexts, one context per test\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/check.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/plugins/check.ts","line":700,"symbol":"instrument.chokepoint.guarded(\"chokepoint\") callback.run","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/convex.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/convex.test.ts","line":27,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/plugins/convex.test.ts","line":69,"symbol":"test(\"the Convex plugin grades a Convex project's chokepoint: a function reached through the generated API outside it is a bypass, its refutation stages th...) callback.graded","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/convex.test.ts","line":187,"symbol":"test(\"a use of the generated API the Convex plugin cannot read through is a named gap that keeps the chokepoint from passing, never silence; an alias, a de...) callback.graded","class":"test","of":"protected","test":true},{"file":"src/plugins/plugins.test.ts","line":17,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/plugins/plugins.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/plugins.test.ts","line":104,"symbol":"test(\"a plugin that extends a language answers its chokepoint checks: the adapter is the plugin's, wrapping the core's, and the run entry names the plugin\") callback.checked","class":"test","of":"protected","test":true},{"file":"src/plugins/plugins.test.ts","line":107,"symbol":"test(\"a plugin that extends a language answers its chokepoint checks: the adapter is the plugin's, wrapping the core's, and the run entry names the plugin\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":126,"symbol":"test(\"a via form is proved by the plugin that declares it, graded like a test with its evidence label; a form no plugin declares is a spec problem naming t...) callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":207,"symbol":"test(\"a verifier's command must name what it proves, and with a match its exit 0 passes only when its output matches\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/quint.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/quint.test.ts","line":114,"symbol":"test(\"a Quint bullet is proved through the verifier role: graded like a test with its evidence label, the plugin named, a counterexample failing it, [quint...) callback.record.withQuint() callback","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":71,"files":["src/adapters/declared-server.test.ts","src/adapters/declared.test.ts","src/adapters/project-files.test.ts","src/adapters/python-from.test.ts","src/adapters/python.test.ts","src/adapters/rust.test.ts","src/adapters/tach.test.ts","src/enforcement/check.ts","src/enforcement/cli.ts","src/enforcement/enforcement.test.ts","src/enforcement/from.test.ts","src/enforcement/javascript.test.ts","src/enforcement/languages.test.ts","src/enforcement/run.ts","src/enforcement/server.test.ts","src/lifecycle/hook.ts","src/lifecycle/monorepo.test.ts","src/observation/observation.test.ts","src/plugins/check.ts","src/plugins/convex.test.ts","src/plugins/plugins.test.ts","src/plugins/quint.test.ts"],"latency":234,"reason":"checkChokepoint is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/check.ts:204 reads \"export async function checkChokepoint(adapter: LanguageAdapt\"); every reference in the project is inside the chokepoint; 71 test references","state":"invariant","enforces":["performRun"]},{"component":"src/enforcement","name":"one invocation for every test","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/adapters/declared.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/declared.test.ts","line":167,"symbol":"test(\"a run routes a declared language's chokepoint to its adapter and records which language answered; a mixed project picks it by the files the component...) callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/python.test.ts","line":434,"symbol":"test(\"the totality oracle pass through pytest: every test the bullets name in one invocation, mapped back from the JUnit report\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":445,"symbol":"test(\"the totality oracle pass through pytest: every test the bullets name in one invocation, mapped back from the JUnit report\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":454,"symbol":"test(\"the totality oracle pass through pytest: every test the bullets name in one invocation, mapped back from the JUnit report\") callback.missing","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/python.test.ts","line":517,"symbol":"test(\"a run over the Python fixture records the grade, the enforcer, and the refutation per chokepoint\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/cli.ts","line":29,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/enforcement/cli.ts","line":266,"symbol":"runCommand.outcome","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/cli.ts","line":268,"symbol":"runCommand","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/cli.ts","line":419,"symbol":"refuteCommand.outcome","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/enforcement.test.ts","line":27,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":220,"symbol":"test(\"run sites persist protected references and chokepoint references without turning an unused import into a call\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":278,"symbol":"test(\"the batched totality oracle pass: every test the bullets name in one invocation, mapped back by name; the record says which mode ran\") callback.runTotalityBatch","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":307,"symbol":"test(\"the batched totality oracle pass: every test the bullets name in one invocation, mapped back by name; the record says which mode ran\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":313,"symbol":"test(\"the batched totality oracle pass: every test the bullets name in one invocation, mapped back by name; the record says which mode ran\") callback.single","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":337,"symbol":"test(\"a run appends one record, never rewrites; spec --check reads the run; the status view derives the latest verdict and keeps a skipped one dated\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":367,"symbol":"test(\"a run appends one record, never rewrites; spec --check reads the run; the status view derives the latest verdict and keeps a skipped one dated\") callback.second","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":407,"symbol":"test(\"reference-query failures and legacy records never masquerade as confirmed empty sites\") callback.failed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":921,"symbol":"test(\"refute runs the bullet's totality oracle with the break staged, requires it to fail, and appends the refutation record\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/from.test.ts","line":144,"symbol":"test(\"the config's chokepointFrom governs a silent bullet, a bullet's own from: overrides it, and the run records and prints which governed\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":159,"symbol":"test(\"the config's chokepointFrom governs a silent bullet, a bullet's own from: overrides it, and the run records and prints which governed\") callback.unset","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":172,"symbol":"test(\"Scope and the agent query show which references governed: the from: line with its exempt count on the enforcement, each exempt site as exempt, and th...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/languages.test.ts","line":215,"symbol":"test(\"each totality oracle's test runs through the setup whose test files hold it, one batched invocation per setup, from the setup's own folder\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":229,"symbol":"test(\"each totality oracle's test runs through the setup whose test files hold it, one batched invocation per setup, from the setup's own folder\") callback.each","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":244,"symbol":"test(\"each chokepoint resolves and grades through its own language's warm server, and a run or an edit reaches only the languages its checks need\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/languages.test.ts","line":260,"symbol":"test(\"each chokepoint resolves and grades through its own language's warm server, and a run or an edit reaches only the languages its checks need\") callback.one","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/run.ts","line":30,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/enforcement/run.ts","line":356,"symbol":"performRun.pass.result","class":"inside","of":"protected","test":false},{"file":"src/enforcement/server.test.ts","line":16,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/server.test.ts","line":132,"symbol":"test(\"the run keeps the instrument alive across the test pass, and a run whose instrument died exits non-zero with the reason\") callback.died","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/server.test.ts","line":145,"symbol":"test(\"the run keeps the instrument alive across the test pass, and a run whose instrument died exits non-zero with the reason\") callback.kept","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.ts","line":79,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":684,"symbol":"checkAtEdit.outcome","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/observation/observation.test.ts","line":26,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/observation/observation.test.ts","line":146,"symbol":"observedRun","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":150,"symbol":"observedRun","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":409,"symbol":"test(\"the Python fixture observed through coverage.py dynamic contexts, one context per test\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/check.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/plugins/check.ts","line":700,"symbol":"instrument.chokepoint.guarded(\"chokepoint\") callback.run","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/convex.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/convex.test.ts","line":69,"symbol":"test(\"the Convex plugin grades a Convex project's chokepoint: a function reached through the generated API outside it is a bypass, its refutation stages th...) callback.graded","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/plugins.test.ts","line":107,"symbol":"test(\"a plugin that extends a language answers its chokepoint checks: the adapter is the plugin's, wrapping the core's, and the run entry names the plugin\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":126,"symbol":"test(\"a via form is proved by the plugin that declares it, graded like a test with its evidence label; a form no plugin declares is a spec problem naming t...) callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":207,"symbol":"test(\"a verifier's command must name what it proves, and with a match its exit 0 passes only when its output matches\") callback.outcome","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/quint.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/quint.test.ts","line":114,"symbol":"test(\"a Quint bullet is proved through the verifier role: graded like a test with its evidence label, the plugin named, a counterexample failing it, [quint...) callback.record.withQuint() callback","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":1,"files":["src/adapters/declared.test.ts","src/adapters/python.test.ts","src/enforcement/cli.ts","src/enforcement/enforcement.test.ts","src/enforcement/from.test.ts","src/enforcement/languages.test.ts","src/enforcement/run.ts","src/enforcement/server.test.ts","src/enforcement/totality.ts","src/lifecycle/hook.ts","src/observation/observation.test.ts","src/plugins/check.ts","src/plugins/convex.test.ts","src/plugins/plugins.test.ts","src/plugins/quint.test.ts"],"latency":229,"reason":"runTotalityBatch is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/totality.ts:268 reads \"export async function runTotalityBatch(root: string, config:\"); every reference in the project is inside the chokepoint; 1 test reference","state":"invariant","enforces":["performRun"]},{"component":"src/enforcement","name":"warm server the only path","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/economy/cli.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/economy/cli.ts","line":54,"symbol":"economyFor","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/run.ts","line":29,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/enforcement/run.ts","line":607,"symbol":"performRun","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/run.ts","line":721,"symbol":"withWarmAdapter","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/run.ts","line":757,"symbol":"withWarmAdapters.open","class":"inside","of":"protected","test":false},{"file":"src/enforcement/server.test.ts","line":15,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/enforcement/server.test.ts","line":56,"symbol":"test(\"two clients ask the same questions; the second finds the server warm\") callback.first","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":69,"symbol":"test(\"two clients ask the same questions; the second finds the server warm\") callback.second","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":83,"symbol":"test(\"a served refutation stages what the adapter in process stages, the exempt folder and the occasion carried\") callback.served","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":103,"symbol":"test(\"a client with spawning off fails plainly when nothing listens\") callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":201,"symbol":"stopAll.connected","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":245,"symbol":"test(\"a lock whose owner is dead is reclaimed by the next client\") callback.connected","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":267,"symbol":"test(\"serve refuses a root a live server holds and never unlinks that server's socket\") callback.connected","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":281,"symbol":"test(\"a server running other code is replaced by a fresh process\") callback.old","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":287,"symbol":"test(\"a server running other code is replaced by a fresh process\") callback.fresh","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":365,"symbol":"test(\"a socket client without the root's token is refused, and the token lives only in files this user can read\") callback.connected","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":449,"symbol":"test(\"HTTP answers on loopback alone and refuses a request without the token, addressed to another server or sent from another site, or not a GET, and send...) callback.connected","class":"test","of":"protected","test":true},{"file":"src/enforcement/server.test.ts","line":500,"symbol":"test(\"an HTTP client that never finishes its headers is cut off\") callback.connected","class":"test","of":"protected","test":true},{"file":"src/readings/scope/live.test.ts","line":13,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/readings/scope/live.test.ts","line":37,"symbol":"live.connected","class":"test","of":"protected","test":true}],"testReferences":15,"files":["src/economy/cli.ts","src/enforcement/run.ts","src/enforcement/server.test.ts","src/enforcement/server.ts","src/readings/scope/live.test.ts"],"latency":192,"reason":"connectAdapter is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/server.ts:917 reads \"export async function connectAdapter(rootGiven: string, opti\"); every reference in the project is inside the chokepoint; 15 test references","state":"invariant","enforces":["withWarmAdapters"]},{"component":"src/journal","name":"a record is vetted before it is written","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/journal/shards.test.ts","line":24,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/journal/shards.test.ts","line":94,"symbol":"appendAll","class":"test","of":"protected","test":true},{"file":"src/journal/workVerbs.ts","line":27,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/journal/workVerbs.ts","line":37,"symbol":"writeWork","class":"inside","of":"protected","test":false},{"file":"src/journal/workVerbs.ts","line":59,"symbol":"create.file","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/workVerbs.ts","line":82,"symbol":"move.file","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/workVerbs.ts","line":94,"symbol":"close.file","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/workVerbs.ts","line":108,"symbol":"owner.file","class":"chokepoint-reference","of":"chokepoint","test":false}],"testReferences":2,"files":["src/journal/shards.test.ts","src/journal/work.ts","src/journal/workVerbs.ts"],"latency":186,"reason":"appendWork is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/work.ts:43 reads \"export function appendWork(cwd: string, record: WorkRecord):\"); every reference in the project is inside the chokepoint; 2 test references","state":"invariant","enforces":["writeWork"]},{"component":"src/journal","name":"append-only store","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/cli.ts","line":52,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/cli.ts","line":249,"symbol":"lexiconCommand.named","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/economy/calibrate.ts","line":26,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/economy/calibrate.ts","line":133,"symbol":"calibrate.journal","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/economy/economy.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/economy/economy.test.ts","line":196,"symbol":"test(\"calibrate: the outcome label is automatic; a later defect record labels defect, a later passing run labels clean, nothing later is unknown, and a lab...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/cli.ts","line":31,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/enforcement/cli.ts","line":412,"symbol":"refuteCommand","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/run.ts","line":21,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/enforcement/run.ts","line":524,"symbol":"performRun.pass","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/run.ts","line":693,"symbol":"confirmEach","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/test-budgets.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/test-budgets.test.ts","line":76,"symbol":"test(\"the time ceiling fails a test that runs past it, nested or called back, in its own file's name and place, and holds a test that declares a budget cit...) callback.decision","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/test-budgets.ts","line":177,"symbol":"decisionHeld.loadJournal","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/branches.ts","line":12,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/branches.ts","line":38,"symbol":"recordsOnOtherBranches.out","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/cli.ts","line":33,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/cli.ts","line":33,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/cli.ts","line":100,"symbol":"read.guarded() callback.loaded","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/cli.ts","line":124,"symbol":"read.guarded() callback","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/convergence.ts","line":31,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/convergence.ts","line":204,"symbol":"convergence.states","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/dead-ends.ts","line":58,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/dead-ends.ts","line":58,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/dead-ends.ts","line":259,"symbol":"DeadEndReading.worktrees","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/dead-ends.ts","line":276,"symbol":"readDeadEnds.loaded","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/defects.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/journal/defects.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/journal/defects.test.ts","line":108,"symbol":"test(\"a defect carries a declared class, where it came in and what caught it, and a value outside each vocabulary is refused before anything is written\") callback.records","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":113,"symbol":"test(\"a defect carries a declared class, where it came in and what caught it, and a value outside each vocabulary is refused before anything is written\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":125,"symbol":"test(\"a defect carries a declared class, where it came in and what caught it, and a value outside each vocabulary is refused before anything is written\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":158,"symbol":"test(\"classify folds into the defect without editing it: a later classification overrides, a retracted one gives nothing, and a field nobody gave stays unk...) callback.records","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":167,"symbol":"test(\"classify folds into the defect without editing it: a later classification overrides, a retracted one gives nothing, and a field nobody gave stays unk...) callback.blank","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":190,"symbol":"test(\"resolved closes a defect with a guard a spec declares or a decision, refuses a guard or decision that names nothing, and a retracted close can be clo...) callback.record","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":192,"symbol":"test(\"resolved closes a defect with a guard a spec declares or a decision, refuses a guard or decision that names nothing, and a retracted close can be clo...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":372,"symbol":"test(\"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, ...) callback.unlabelled","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":378,"symbol":"test(\"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, ...) callback.records0","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":415,"symbol":"test(\"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, ...) callback.records","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":453,"symbol":"test(\"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\") callback.records","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":463,"symbol":"test(\"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\") callback.record","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":485,"symbol":"test(\"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":499,"symbol":"test(\"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":518,"symbol":"test(\"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\") callback.placed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":523,"symbol":"test(\"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":568,"symbol":"test(\"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end read...) callback.own","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":570,"symbol":"test(\"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end read...) callback.across","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":596,"symbol":"test(\"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end read...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":598,"symbol":"test(\"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end read...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":620,"symbol":"test(\"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end read...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":636,"symbol":"test(\"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end read...) callback.fromBare","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":653,"symbol":"test(\"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end read...) callback.fromNested","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/feed.ts","line":45,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/feed.ts","line":45,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/feed.ts","line":45,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/feed.ts","line":45,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/feed.ts","line":79,"symbol":"latestCursor","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":90,"symbol":"openFeed.keys","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":91,"symbol":"openFeed.latest","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":121,"symbol":"peerFeed.keys","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":124,"symbol":"peerFeed.loaded","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":202,"symbol":"leaveReturn.records","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":231,"symbol":"returnFeed.byId","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/journal.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/journal/journal.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/journal/journal.test.ts","line":63,"symbol":"lines","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":67,"symbol":"records","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":286,"symbol":"test(\"a damaged line is reported with its file and line number, skipped, and counted\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":287,"symbol":"test(\"a damaged line is reported with its file and line number, skipped, and counted\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":502,"symbol":"test(\"citations resolve at the write: an unknown id refuses the write, a record of any kind in either store is accepted, and records without citations stil...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":503,"symbol":"test(\"citations resolve at the write: an unknown id refuses the write, a record of any kind in either store is accepted, and records without citations stil...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":537,"symbol":"test(\"citations resolve at the write: an unknown id refuses the write, a record of any kind in either store is accepted, and records without citations stil...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":646,"symbol":"test(\"a flag's value may come from a file or standard input, so long text never meets the shell\") callback.record","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":671,"symbol":"test(\"a record the vet stands against is refused before anything is written\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":694,"symbol":"test(\"the command line acts on the project from any subfolder, and vets a record against the project's rejected names\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":699,"symbol":"test(\"the command line acts on the project from any subfolder, and vets a record against the project's rejected names\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/journal.test.ts","line":719,"symbol":"test(\"a record committed on another branch may be cited and read, and says where it is; an id found nowhere is still refused\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/read.ts","line":24,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/read.ts","line":24,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/read.ts","line":24,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/read.ts","line":186,"symbol":"renderTimeline","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/read.ts","line":199,"symbol":"renderJson","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/read.ts","line":228,"symbol":"renderOne","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/read.ts","line":258,"symbol":"renderDamaged","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/read.ts","line":290,"symbol":"after","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/read.ts","line":309,"symbol":"recordsAfter","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/read.ts","line":319,"symbol":"renderSubjects","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/shards.test.ts","line":22,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/journal/shards.test.ts","line":22,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/journal/shards.test.ts","line":22,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/journal/shards.test.ts","line":22,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/journal/shards.test.ts","line":93,"symbol":"appendAll","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":123,"symbol":"ids","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":163,"symbol":"test(\"a writer starts a new shard when HEAD, the branch or the size limit moved, and never appends to a shard a commit holds\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":164,"symbol":"test(\"a writer starts a new shard when HEAD, the branch or the size limit moved, and never appends to a shard a commit holds\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":167,"symbol":"test(\"a writer starts a new shard when HEAD, the branch or the size limit moved, and never appends to a shard a commit holds\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":174,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":176,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":179,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":182,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":190,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":194,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":200,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":201,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":251,"symbol":"test(\"every reader reads a packed shard's records as a line shard's: the journal, the runs, the work orders, the run index, the citation search, the record...) callback.packed() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":258,"symbol":"test(\"every reader reads a packed shard's records as a line shard's: the journal, the runs, the work orders, the run index, the citation search, the record...) callback.journal","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":261,"symbol":"test(\"every reader reads a packed shard's records as a line shard's: the journal, the runs, the work orders, the run index, the citation search, the record...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":357,"symbol":"test(\"two checkouts of one session on parallel and stacked branches, landed by merge, squash and rebase with no attributes file, conflict nowhere, and ever...) callback.loaded","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/shards.test.ts","line":373,"symbol":"test(\"the tree's dirty check never rewrites git's index, so the next record's shard check does not read it\") callback.state","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/store.ts","line":26,"symbol":"journalDir","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":35,"symbol":"sessionFile","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":35,"symbol":"sessionFile","class":"inside","of":"protected","test":false},{"file":"src/journal/store.ts","line":46,"symbol":"appendRecord","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":51,"symbol":"appendRecordTo","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":53,"symbol":"appendRecordTo","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":53,"symbol":"appendRecordTo","class":"inside","of":"protected","test":false},{"file":"src/journal/store.ts","line":57,"symbol":"appendRecordTo.file","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":69,"symbol":"Loaded.damaged","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":79,"symbol":"loadJournal","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":80,"symbol":"loadJournal","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":89,"symbol":"journalFileKeys.dir","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":89,"symbol":"journalFileKeys.dir","class":"inside","of":"protected","test":false},{"file":"src/journal/store.ts","line":104,"symbol":"loadJournalFiles","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":105,"symbol":"loadJournalFiles.dir","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":105,"symbol":"loadJournalFiles.dir","class":"inside","of":"protected","test":false},{"file":"src/journal/store.ts","line":106,"symbol":"loadJournalFiles.loaded","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":120,"symbol":"loadJournalFiles.file","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":126,"symbol":"loadJournalFiles.file","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":132,"symbol":"loadJournalFiles","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":146,"symbol":"LoadedAcross","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":148,"symbol":"LoadedAcross.worktrees","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":190,"symbol":"storeFiles","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":203,"symbol":"storeNames","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":241,"symbol":"loadJournalAcrossWorktrees","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":242,"symbol":"loadJournalAcrossWorktrees.loaded","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":246,"symbol":"loadJournalAcrossWorktrees","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":246,"symbol":"loadJournalAcrossWorktrees","class":"inside","of":"protected","test":false},{"file":"src/journal/store.ts","line":246,"symbol":"loadJournalAcrossWorktrees","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":250,"symbol":"loadJournalAcrossWorktrees.file","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":258,"symbol":"loadJournalAcrossWorktrees","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":264,"symbol":"loadJournalAcrossWorktrees.dir","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":264,"symbol":"loadJournalAcrossWorktrees.dir","class":"inside","of":"protected","test":false},{"file":"src/journal/store.ts","line":265,"symbol":"loadJournalAcrossWorktrees.worktree","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/store.ts","line":304,"symbol":"loadJournalAcrossWorktrees","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":55,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/verbs.ts","line":55,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/verbs.ts","line":55,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/verbs.ts","line":55,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/verbs.ts","line":55,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/verbs.ts","line":103,"symbol":"head","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":143,"symbol":"citedWhere.local","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":161,"symbol":"answerable","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":162,"symbol":"answerable.loaded","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":178,"symbol":"write","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":191,"symbol":"target","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":201,"symbol":"pointers","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":205,"symbol":"refuseIfAnswered","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":599,"symbol":"enact.gaps","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/workVerbs.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/workVerbs.ts","line":203,"symbol":"inspect.lines","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/delivery.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/delivery.ts","line":100,"symbol":"deliveries.records","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.test.ts","line":12,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook.test.ts","line":288,"symbol":"test(\"an unacknowledged escalation heads the start output; an acknowledged one does not\") callback.open","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":313,"symbol":"test(\"an open escalation that cites a decision and a work order names each by id, kind and subject in the start output\") callback.escalation","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.ts","line":98,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":290,"symbol":"escalationBlock.journal","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.ts","line":323,"symbol":"unableWalls","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.ts","line":826,"symbol":"startReading.named","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-baseline.ts","line":24,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/lexicon-baseline.ts","line":89,"symbol":"readBaseline","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-coverage.ts","line":41,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/lexicon-coverage.ts","line":164,"symbol":"rulings","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-maintain.ts","line":16,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/lexicon-maintain.ts","line":16,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/lexicon-maintain.ts","line":464,"symbol":"appliedDecision","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-maintain.ts","line":477,"symbol":"rejectingDecisions","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-maintain.ts","line":545,"symbol":"applyProposal","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-maintain.ts","line":597,"symbol":"recoverLexicon.locked() callback","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-maintain.ts","line":614,"symbol":"reviewLexicon","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-work.test.ts","line":28,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/lexicon-work.test.ts","line":155,"symbol":"test(\"lexicon maintenance preserves full entries, records actual effects, and refuses stale previews and unacknowledged retirement\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/lexicon-work.test.ts","line":187,"symbol":"test(\"lexicon maintenance preserves full entries, records actual effects, and refuses stale previews and unacknowledged retirement\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/lexicon-work.test.ts","line":245,"symbol":"test(\"lexicon application recovers a journal failure without lying about an unapplied change or duplicating its decision\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/lexicon-work.test.ts","line":247,"symbol":"test(\"lexicon application recovers a journal failure without lying about an unapplied change or duplicating its decision\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/lexicon-work.test.ts","line":809,"symbol":"test(\"a define keeps every property and detail key unless one is dropped by name, and the applying decision carries the dropped text\") callback.decision","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/lexicon-work.test.ts","line":883,"symbol":"test(\"a rejection is lifted only with a human acknowledgement and a cite of the decision that rejected it\") callback.decision","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/practice-delivery.ts","line":22,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/practice-delivery.ts","line":187,"symbol":"practiceStopText","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/state-files.test.ts","line":9,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/state-files.test.ts","line":100,"symbol":"assertAllLoad.journal","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/state-files.test.ts","line":142,"symbol":"test(\"a torn last line a union merge keeps stays one damaged line, the record appended after it reads whole, and a line kept twice is read once\") callback.journal","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/statusline.test.ts","line":8,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/statusline.test.ts","line":37,"symbol":"test(\"the status line reads where the hooks keep the session's records, by the hooks' own names and budget\") callback.journal","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-state.ts","line":37,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/vocabulary-state.ts","line":342,"symbol":"recordKeys.out","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/work-meter.test.ts","line":39,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":684,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":687,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":694,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":728,"symbol":"test(\"Stop reuses a complete vocabulary reading until a project file or record changes\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observed.ts","line":12,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/observation/observed.ts","line":163,"symbol":"observedCommand.head","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/query/cli.ts","line":29,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/readings/query/cli.ts","line":86,"symbol":"queryCommand.journal.records","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/scope/build.ts","line":36,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/readings/scope/build.ts","line":273,"symbol":"loadState.journal","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/scope/gaps.ts","line":59,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/readings/scope/gaps.ts","line":473,"symbol":"readGapBaseline","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/scope/live.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/live.test.ts","line":238,"symbol":"test(\"the first load stays flat as the journal and the runs grow, every derived verdict is unchanged, and history loads every record left out by cursor, on...) callback.allJournal","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/live.ts","line":40,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/readings/scope/live.ts","line":238,"symbol":"LiveReading.refresh.loaded","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/spec/practice.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/practice.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/practice.test.ts","line":190,"symbol":"test(\"a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":255,"symbol":"test(\"an enactment needs an outcome for every step, a because for a deviation or a skip, and keeps the text it enacted\") callback.e","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":282,"symbol":"test(\"a step enacted and since removed is a problem until a decision cites an enactment of the practice\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":284,"symbol":"test(\"a step enacted and since removed is a problem until a decision cites an enactment of the practice\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":300,"symbol":"test(\"enact refuses a practice that has lost a step an enactment taught until a decision amends it\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":306,"symbol":"test(\"enact refuses a practice that has lost a step an enactment taught until a decision amends it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":310,"symbol":"test(\"enact refuses a practice that has lost a step an enactment taught until a decision amends it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practices.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/spec/practices.ts","line":244,"symbol":"journalRecords","class":"chokepoint-reference","of":"chokepoint","test":false}],"testReferences":0,"files":["src/cli.ts","src/economy/calibrate.ts","src/economy/economy.test.ts","src/enforcement/cli.ts","src/enforcement/run.ts","src/enforcement/test-budgets.test.ts","src/enforcement/test-budgets.ts","src/journal/branches.ts","src/journal/cli.ts","src/journal/convergence.ts","src/journal/dead-ends.ts","src/journal/defects.test.ts","src/journal/feed.ts","src/journal/journal.test.ts","src/journal/read.ts","src/journal/shards.test.ts","src/journal/store.ts","src/journal/verbs.ts","src/journal/workVerbs.ts","src/lifecycle/delivery.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/lexicon-baseline.ts","src/lifecycle/lexicon-coverage.ts","src/lifecycle/lexicon-maintain.ts","src/lifecycle/lexicon-work.test.ts","src/lifecycle/practice-delivery.ts","src/lifecycle/state-files.test.ts","src/lifecycle/statusline.test.ts","src/lifecycle/vocabulary-state.ts","src/lifecycle/work-meter.test.ts","src/observation/observed.ts","src/readings/query/cli.ts","src/readings/scope/build.ts","src/readings/scope/gaps.ts","src/readings/scope/live.test.ts","src/readings/scope/live.ts","src/spec/practice.test.ts","src/spec/practices.ts"],"latency":371,"reason":"journalDir is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/store.ts:25 reads \"export function journalDir(cwd: string): string {\"); every reference in the project is inside the chokepoint","state":"invariant","enforces":["src/journal/store.ts"]},{"component":"src/journal","name":"attributed writes","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/economy/economy.test.ts","line":17,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/economy/economy.test.ts","line":196,"symbol":"test(\"calibrate: the outcome label is automatic; a later defect record labels defect, a later passing run labels clean, nothing later is unknown, and a lab...) callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":22,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/journal/shards.test.ts","line":93,"symbol":"appendAll","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":163,"symbol":"test(\"a writer starts a new shard when HEAD, the branch or the size limit moved, and never appends to a shard a commit holds\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":164,"symbol":"test(\"a writer starts a new shard when HEAD, the branch or the size limit moved, and never appends to a shard a commit holds\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":174,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":176,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":179,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":182,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":190,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":194,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":200,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":201,"symbol":"test(\"a lost, torn or wrong shard state starts a new shard, and a state that names a committed shard at the current HEAD still never appends to it\") callback","class":"test","of":"protected","test":true},{"file":"src/journal/shards.test.ts","line":251,"symbol":"test(\"every reader reads a packed shard's records as a line shard's: the journal, the runs, the work orders, the run index, the citation search, the record...) callback.packed() callback","class":"test","of":"protected","test":true},{"file":"src/journal/verbs.ts","line":230,"symbol":"decide","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":243,"symbol":"retract","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":261,"symbol":"conjecture","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":295,"symbol":"resolved","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":316,"symbol":"resolved","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":353,"symbol":"classify","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":365,"symbol":"dismiss","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":447,"symbol":"defect.written","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":486,"symbol":"experimentCreate","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":522,"symbol":"experimentClose","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":531,"symbol":"unable","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":540,"symbol":"escalate","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":552,"symbol":"acknowledge","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":634,"symbol":"enact","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/work-meter.test.ts","line":39,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":684,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":687,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":694,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":728,"symbol":"test(\"Stop reuses a complete vocabulary reading until a project file or record changes\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/practice.test.ts","line":17,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/spec/practice.test.ts","line":284,"symbol":"test(\"a step enacted and since removed is a problem until a decision cites an enactment of the practice\") callback","class":"test","of":"protected","test":true}],"testReferences":22,"files":["src/economy/economy.test.ts","src/journal/shards.test.ts","src/journal/store.ts","src/journal/verbs.ts","src/lifecycle/work-meter.test.ts","src/spec/practice.test.ts"],"latency":130,"reason":"appendRecord is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/store.ts:45 reads \"export function appendRecord(cwd: string, record: JournalRec\"); every reference in the project is inside the chokepoint; 22 test references","state":"invariant","enforces":["write in verbs.ts"]},{"component":"src/journal","name":"one id minter","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/journal/verbs.ts","line":27,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/journal/verbs.ts","line":104,"symbol":"head.id","class":"inside","of":"protected","test":false},{"file":"src/journal/verbs.ts","line":229,"symbol":"decide.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":242,"symbol":"retract.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":255,"symbol":"conjecture.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":294,"symbol":"resolved.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":305,"symbol":"resolved.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":352,"symbol":"classify.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":364,"symbol":"dismiss.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":438,"symbol":"defect.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":470,"symbol":"experimentCreate.base","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":521,"symbol":"experimentClose.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":530,"symbol":"unable.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":539,"symbol":"escalate.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":551,"symbol":"acknowledge.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/verbs.ts","line":623,"symbol":"enact.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/vocabularies.test.ts","line":9,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/journal/vocabularies.test.ts","line":111,"symbol":"test(\"every closed list the journal verbs take is read from the record model, and every help line, doc and definition that enumerates one names exactly its...) callback.id","class":"test","of":"protected","test":true},{"file":"src/journal/workVerbs.ts","line":26,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/workVerbs.ts","line":58,"symbol":"create.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/workVerbs.ts","line":81,"symbol":"move.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/workVerbs.ts","line":93,"symbol":"close.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/workVerbs.ts","line":107,"symbol":"owner.record.","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/scope/practices.test.ts","line":9,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/readings/scope/practices.test.ts","line":131,"symbol":"test(\"a citation's kind is read off the minter's tables: an id of every journal and work kind names its kind, and a practice's evidence counts each\") callback.minted.map() callback.id","class":"test","of":"protected","test":true},{"file":"src/readings/scope/practices.test.ts","line":132,"symbol":"test(\"a citation's kind is read off the minter's tables: an id of every journal and work kind names its kind, and a practice's evidence counts each\") callback.minted.map() callback.id","class":"test","of":"protected","test":true}],"testReferences":5,"files":["src/journal/record.ts","src/journal/verbs.ts","src/journal/vocabularies.test.ts","src/journal/workVerbs.ts","src/readings/scope/practices.test.ts"],"latency":177,"reason":"recordId is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/record.ts:287 reads \"export function recordId(kind: Kind | WorkKind, session: str\"); every reference in the project is inside the chokepoint; 5 test references","state":"invariant","enforces":["head in verbs.ts"]},{"component":"src/lifecycle","name":"regulate refuses only what it can prove","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/cli.ts","line":54,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/cli.ts","line":278,"symbol":"hookCommand.result","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/enforcement.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":472,"symbol":"test(\"PostToolUse on a file-writing tool re-checks the invariants that may involve the file and prints the bypass with the two options; Stop carries the de...) callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":484,"symbol":"test(\"PostToolUse on a file-writing tool re-checks the invariants that may involve the file and prints the bypass with the two options; Stop carries the de...) callback.reading","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":486,"symbol":"test(\"PostToolUse on a file-writing tool re-checks the invariants that may involve the file and prints the bypass with the two options; Stop carries the de...) callback.unrelated","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-serve.ts","line":36,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook-serve.ts","line":119,"symbol":"hookServer.one.result","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook-speed.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook-speed.test.ts","line":68,"symbol":"test(\"a stop starts the snapshot detached, with a fingerprint that moves only with the patch, and reports the newest one already recorded\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":70,"symbol":"test(\"a stop starts the snapshot detached, with a fingerprint that moves only with the patch, and reports the newest one already recorded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":72,"symbol":"test(\"a stop starts the snapshot detached, with a fingerprint that moves only with the patch, and reports the newest one already recorded\") callback.edited","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":88,"symbol":"test(\"a session start and every prompt warm the instrument without waiting for it, and no other event does\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":185,"symbol":"test(\"a tool call's hooks spawn git a fixed number of times, whatever the number of components and practices\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":207,"symbol":"test(\"the vocabulary coverage reading runs at a tool hook only after a write, and at a prompt only when the tree moved\") callback.hook","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":14,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/hook.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook.test.ts","line":107,"symbol":"test(\"SessionStart and SubagentStart inject both lexicons and the instruction as additionalContext\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":130,"symbol":"test(\"Coherence's own start hooks name its source-tree journal command\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":149,"symbol":"test(\"a session start in a project that adopted an earlier release writes the attributes file its records merge by and brings the earlier ignore file up so...) callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":161,"symbol":"test(\"UserPromptSubmit and PostToolUse print nothing\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":167,"symbol":"test(\"Stop and SubagentStop with a clean working tree are silent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":168,"symbol":"test(\"Stop and SubagentStop with a clean working tree are silent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":176,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":184,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":185,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/hook.test.ts","line":190,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":200,"symbol":"test(\"an unknown noun in a changed file is advisory: Stop reports it and SubagentStop never refuses on it\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":216,"symbol":"test(\"in an adopter, Coherence's rejected names in the project's own code, prose and specs never refuse a subagent stop, and the stop names none of them\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":232,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.refused","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":233,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/hook.test.ts","line":235,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.excused","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":240,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.other","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":241,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/hook.test.ts","line":246,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.problem","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":247,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/hook.test.ts","line":249,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.allowed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":268,"symbol":"test(\"changedFiles reports a git failure instead of answering a clean tree; outside git the answer is no files\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":272,"symbol":"test(\"changedFiles reports a git failure instead of answering a clean tree; outside git the answer is no files\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":291,"symbol":"test(\"an unacknowledged escalation heads the start output; an acknowledged one does not\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":300,"symbol":"test(\"an unacknowledged escalation heads the start output; an acknowledged one does not\") callback.after","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":315,"symbol":"test(\"an open escalation that cites a decision and a work order names each by id, kind and subject in the start output\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":337,"symbol":"test(\"the start injection stays under the budget with escalations present: the vocabulary decays from its least recently named concept, to names and then t...) callback.context","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":354,"symbol":"test(\"the start injection stays under the budget with escalations present: the vocabulary decays from its least recently named concept, to names and then t...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":367,"symbol":"test(\"the start injection stays under the budget with escalations present: the vocabulary decays from its least recently named concept, to names and then t...) callback.light","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":408,"symbol":"test(\"the hook refuses a cwd from stdin that is not inside the project root it was installed for\") callback.ok","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":413,"symbol":"test(\"the hook refuses a cwd from stdin that is not inside the project root it was installed for\") callback.out","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":446,"symbol":"test(\"the Stop snapshot reaches the instrument through enforcement's one door, in production as in a test\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":457,"symbol":"test(\"the Stop snapshot reaches the instrument through enforcement's one door, in production as in a test\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":508,"symbol":"test(\"orient lists open requirements and regulate reports them; only spec problems refuse a subagent stop\") callback.hook","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":508,"symbol":"test(\"orient lists open requirements and regulate reports them; only spec problems refuse a subagent stop\") callback.refuseExit","class":"test","of":"protected","test":true},{"file":"src/lifecycle/hook.test.ts","line":545,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.silent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":549,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.open","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":552,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":555,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.active","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":559,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.other","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":563,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":571,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.several","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":576,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":586,"symbol":"test(\"the peer feed injects a peer's decisions and escalations and no other kind\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":597,"symbol":"test(\"the peer feed injects a peer's decisions and escalations and no other kind\") callback.feed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":615,"symbol":"test(\"a subagent's start names its own session and its coordinator's, and says never to write under the coordinator's\") callback.child","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":619,"symbol":"test(\"a subagent's start names its own session and its coordinator's, and says never to write under the coordinator's\") callback.main","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":631,"symbol":"test(\"the main thread's feed counts a record of its own session under another agent's name as a peer's\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":634,"symbol":"test(\"the main thread's feed counts a record of its own session under another agent's name as a peer's\") callback.tool","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":649,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":650,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":655,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":658,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback.unprinted","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":660,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":668,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":678,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":681,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":689,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":703,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":706,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback.tool","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":716,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":717,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":747,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":749,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":757,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback.rendered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":784,"symbol":"gapStarter.start.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":863,"symbol":"test(\"the session's stop starts one background reading of the tree it leaves when the recorded one no longer describes it, and returns without waiting; a s...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":869,"symbol":"test(\"the session's stop starts one background reading of the tree it leaves when the recorded one no longer describes it, and returns without waiting; a s...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":871,"symbol":"test(\"the session's stop starts one background reading of the tree it leaves when the recorded one no longer describes it, and returns without waiting; a s...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":882,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback.opened","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":884,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":888,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":894,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback.sub","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":941,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback.opened","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":943,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":946,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback.message","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":949,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback.sub","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":976,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.plain","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":979,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":980,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":983,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":986,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.silent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":990,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":992,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":994,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.fed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":998,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.overridden","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1005,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1008,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1013,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.refused","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1014,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/hook.test.ts","line":1019,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.reported","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1037,"symbol":"test(\"a hook voice file whose real path leaves the project root is named as not read and never followed\") callback.linked","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1044,"symbol":"test(\"a hook voice file whose real path leaves the project root is named as not read and never followed\") callback.folder","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1054,"symbol":"test(\"a hook voice file whose real path leaves the project root is named as not read and never followed\") callback.inside","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.ts","line":1547,"symbol":"runHook.respond.exit","class":"inside","of":"protected","test":false},{"file":"src/lifecycle/install.test.ts","line":9,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/install.test.ts","line":542,"symbol":"test(\"a located Coherence answers, and refuses, as a direct command does\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/lexicon-work.test.ts","line":417,"symbol":"test(\"lexicon lifecycle uses child identities and installed roots, and advances changed contexts only after delivery\") callback.runHook","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/mirrors.test.ts","line":7,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/mirrors.test.ts","line":79,"symbol":"edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/monorepo.test.ts","line":78,"symbol":"test(\"a hook at the repository top answers for the one project nested below it, from the event's cwd or the file it writes\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":81,"symbol":"test(\"a hook at the repository top answers for the one project nested below it, from the event's cwd or the file it writes\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":87,"symbol":"test(\"a hook at the repository top answers for the one project nested below it, from the event's cwd or the file it writes\") callback.ls","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":103,"symbol":"test(\"a session at the repository top gets orient once, at its first tool use inside the project, and nothing for work elsewhere\") callback.hook.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":158,"symbol":"test(\"an event outside every project is ignored: no answer, nothing written, wherever the session started\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/registry.test.ts","line":101,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":103,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.inNotebooks","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":108,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.inErrors","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":112,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":116,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":137,"symbol":"test(\"the first tool use inside a nested project warms its instrument, once\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":154,"symbol":"test(\"an event outside every leaf of a registry spawns no git and writes nothing\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/stop-delivery.test.ts","line":84,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.pre","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":86,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":92,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":97,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.advisory","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":103,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":106,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.later","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":117,"symbol":"test(\"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\") callback.slow","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":119,"symbol":"test(\"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\") callback.fast","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":128,"symbol":"test(\"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\") callback.allowed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/telemetry.test.ts","line":231,"symbol":"test(\"telemetry adds no wait to a hook: the flush starts detached at a session start or a stop, and queuing is one appended line\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/version.test.ts","line":8,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/version.test.ts","line":109,"symbol":"test(\"the session start names the Coherence that runs and where it is, and warns when another copy the project reaches differs in version\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":12,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":227,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.quiet","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":231,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":237,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":239,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":255,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":260,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.ordinary","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":265,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":269,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.second","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":273,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":282,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":296,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":300,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":304,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":307,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":91,"symbol":"workOf","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":181,"symbol":"atBothSizes.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":510,"symbol":"test(\"in a project of two languages, an edit's check asks the language the last run graded the invariant in, with that run's whole file list\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":532,"symbol":"test(\"an edit is checked with GIT_LITERAL_PATHSPECS set as without it\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":554,"symbol":"test(\"a spec listing that comes back empty where the project holds specs falls back to the whole model and says so\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":582,"symbol":"test(\"an edit is checked against a spec changed at the same size with its modification time set back\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":604,"symbol":"test(\"an edit's chokepoint check never goes silent because a cache cannot be used\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":716,"symbol":"test(\"Stop reuses a complete vocabulary reading until a project file or record changes\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":745,"symbol":"test(\"an edit over torn or missing vocabulary buckets reads in full, says so, names nothing false and writes nothing derived from them\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":775,"symbol":"test(\"a write no hook saw is caught at the next edit, which reads in full as main does\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":800,"symbol":"test(\"the vocabulary tree key follows sparse checkout file membership\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":869,"symbol":"test(\"a checkout, a pull or a branch switch onto a clean tree moves the tree: the next edit and the next prompt read in full\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":892,"symbol":"test(\"an edit read through the kept vocabulary holds the term it makes recur for the stop, unsaid, as the full reading does\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":908,"symbol":"test(\"an edit whose kept vocabulary was left half-written reads in full and says so\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/practice.test.ts","line":316,"symbol":"test(\"PreToolUse delivers a fired practice whole once per version per session, then one line, and never blocks\") callback.fire.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":344,"symbol":"test(\"regulate names a practice that fired with no enactment since, advisory, and never refuses a subagent stop for it\") callback.fired","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":346,"symbol":"test(\"regulate names a practice that fired with no enactment since, advisory, and never refuses a subagent stop for it\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":351,"symbol":"test(\"regulate names a practice that fired with no enactment since, advisory, and never refuses a subagent stop for it\") callback.settled","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":420,"symbol":"test(\"a shell command that writes a file fires an edit trigger the way an edit tool does, and the text it writes counts as added\") callback.fire.result","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":9,"files":["src/cli.ts","src/enforcement/enforcement.test.ts","src/lifecycle/hook-serve.ts","src/lifecycle/hook-speed.test.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/install.test.ts","src/lifecycle/lexicon-work.test.ts","src/lifecycle/mirrors.test.ts","src/lifecycle/monorepo.test.ts","src/lifecycle/registry.test.ts","src/lifecycle/stop-delivery.test.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/version.test.ts","src/lifecycle/vocabulary-signal.test.ts","src/lifecycle/work-meter.test.ts","src/spec/practice.test.ts"],"latency":250,"reason":"REFUSE_EXIT is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/hook.ts:123 reads \"export const REFUSE_EXIT = 2;\"); every reference in the project is inside the chokepoint; 9 test references","state":"invariant","enforces":["runHook"]},{"component":"src/lifecycle","name":"the hook answers one project","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/cli.ts","line":54,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/cli.ts","line":278,"symbol":"hookCommand.result","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/enforcement.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":472,"symbol":"test(\"PostToolUse on a file-writing tool re-checks the invariants that may involve the file and prints the bypass with the two options; Stop carries the de...) callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":484,"symbol":"test(\"PostToolUse on a file-writing tool re-checks the invariants that may involve the file and prints the bypass with the two options; Stop carries the de...) callback.reading","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":486,"symbol":"test(\"PostToolUse on a file-writing tool re-checks the invariants that may involve the file and prints the bypass with the two options; Stop carries the de...) callback.unrelated","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-serve.ts","line":36,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook-serve.ts","line":119,"symbol":"hookServer.one.result","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook-speed.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook-speed.test.ts","line":68,"symbol":"test(\"a stop starts the snapshot detached, with a fingerprint that moves only with the patch, and reports the newest one already recorded\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":70,"symbol":"test(\"a stop starts the snapshot detached, with a fingerprint that moves only with the patch, and reports the newest one already recorded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":72,"symbol":"test(\"a stop starts the snapshot detached, with a fingerprint that moves only with the patch, and reports the newest one already recorded\") callback.edited","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":88,"symbol":"test(\"a session start and every prompt warm the instrument without waiting for it, and no other event does\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":185,"symbol":"test(\"a tool call's hooks spawn git a fixed number of times, whatever the number of components and practices\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":207,"symbol":"test(\"the vocabulary coverage reading runs at a tool hook only after a write, and at a prompt only when the tree moved\") callback.hook","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":14,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/hook.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook.test.ts","line":107,"symbol":"test(\"SessionStart and SubagentStart inject both lexicons and the instruction as additionalContext\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":130,"symbol":"test(\"Coherence's own start hooks name its source-tree journal command\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":149,"symbol":"test(\"a session start in a project that adopted an earlier release writes the attributes file its records merge by and brings the earlier ignore file up so...) callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":161,"symbol":"test(\"UserPromptSubmit and PostToolUse print nothing\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":167,"symbol":"test(\"Stop and SubagentStop with a clean working tree are silent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":168,"symbol":"test(\"Stop and SubagentStop with a clean working tree are silent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":176,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":184,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":190,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":200,"symbol":"test(\"an unknown noun in a changed file is advisory: Stop reports it and SubagentStop never refuses on it\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":216,"symbol":"test(\"in an adopter, Coherence's rejected names in the project's own code, prose and specs never refuse a subagent stop, and the stop names none of them\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":232,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.refused","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":235,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.excused","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":240,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.other","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":246,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.problem","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":249,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.allowed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":268,"symbol":"test(\"changedFiles reports a git failure instead of answering a clean tree; outside git the answer is no files\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":272,"symbol":"test(\"changedFiles reports a git failure instead of answering a clean tree; outside git the answer is no files\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":291,"symbol":"test(\"an unacknowledged escalation heads the start output; an acknowledged one does not\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":300,"symbol":"test(\"an unacknowledged escalation heads the start output; an acknowledged one does not\") callback.after","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":315,"symbol":"test(\"an open escalation that cites a decision and a work order names each by id, kind and subject in the start output\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":337,"symbol":"test(\"the start injection stays under the budget with escalations present: the vocabulary decays from its least recently named concept, to names and then t...) callback.context","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":354,"symbol":"test(\"the start injection stays under the budget with escalations present: the vocabulary decays from its least recently named concept, to names and then t...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":367,"symbol":"test(\"the start injection stays under the budget with escalations present: the vocabulary decays from its least recently named concept, to names and then t...) callback.light","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":408,"symbol":"test(\"the hook refuses a cwd from stdin that is not inside the project root it was installed for\") callback.ok","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":409,"symbol":"test(\"the hook refuses a cwd from stdin that is not inside the project root it was installed for\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/hook.test.ts","line":413,"symbol":"test(\"the hook refuses a cwd from stdin that is not inside the project root it was installed for\") callback.out","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":414,"symbol":"test(\"the hook refuses a cwd from stdin that is not inside the project root it was installed for\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/hook.test.ts","line":446,"symbol":"test(\"the Stop snapshot reaches the instrument through enforcement's one door, in production as in a test\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":457,"symbol":"test(\"the Stop snapshot reaches the instrument through enforcement's one door, in production as in a test\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":508,"symbol":"test(\"orient lists open requirements and regulate reports them; only spec problems refuse a subagent stop\") callback.hook","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":545,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.silent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":549,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.open","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":552,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":555,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.active","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":559,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.other","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":563,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":571,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.several","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":576,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":586,"symbol":"test(\"the peer feed injects a peer's decisions and escalations and no other kind\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":597,"symbol":"test(\"the peer feed injects a peer's decisions and escalations and no other kind\") callback.feed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":615,"symbol":"test(\"a subagent's start names its own session and its coordinator's, and says never to write under the coordinator's\") callback.child","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":619,"symbol":"test(\"a subagent's start names its own session and its coordinator's, and says never to write under the coordinator's\") callback.main","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":631,"symbol":"test(\"the main thread's feed counts a record of its own session under another agent's name as a peer's\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":634,"symbol":"test(\"the main thread's feed counts a record of its own session under another agent's name as a peer's\") callback.tool","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":649,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":650,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":655,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":658,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback.unprinted","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":660,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":668,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":678,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":681,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":689,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":703,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":706,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback.tool","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":716,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":717,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":747,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":749,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":757,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback.rendered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":784,"symbol":"gapStarter.start.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":863,"symbol":"test(\"the session's stop starts one background reading of the tree it leaves when the recorded one no longer describes it, and returns without waiting; a s...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":869,"symbol":"test(\"the session's stop starts one background reading of the tree it leaves when the recorded one no longer describes it, and returns without waiting; a s...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":871,"symbol":"test(\"the session's stop starts one background reading of the tree it leaves when the recorded one no longer describes it, and returns without waiting; a s...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":882,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback.opened","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":884,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":888,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":894,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback.sub","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":941,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback.opened","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":943,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":946,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback.message","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":949,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback.sub","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":976,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.plain","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":979,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":980,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":983,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":986,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.silent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":990,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":992,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":994,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.fed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":998,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.overridden","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1005,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1008,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1013,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.refused","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1019,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.reported","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1037,"symbol":"test(\"a hook voice file whose real path leaves the project root is named as not read and never followed\") callback.linked","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1044,"symbol":"test(\"a hook voice file whose real path leaves the project root is named as not read and never followed\") callback.folder","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1054,"symbol":"test(\"a hook voice file whose real path leaves the project root is named as not read and never followed\") callback.inside","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.ts","line":1312,"symbol":"runHook.timed","class":"inside","of":"protected","test":false},{"file":"src/lifecycle/hook.ts","line":1370,"symbol":"runHook.respond.exit","class":"inside","of":"protected","test":false},{"file":"src/lifecycle/lexicon-work.test.ts","line":417,"symbol":"test(\"lexicon lifecycle uses child identities and installed roots, and advances changed contexts only after delivery\") callback.runHook","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/mirrors.test.ts","line":7,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/mirrors.test.ts","line":79,"symbol":"edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/monorepo.test.ts","line":78,"symbol":"test(\"a hook at the repository top answers for the one project nested below it, from the event's cwd or the file it writes\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":81,"symbol":"test(\"a hook at the repository top answers for the one project nested below it, from the event's cwd or the file it writes\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":87,"symbol":"test(\"a hook at the repository top answers for the one project nested below it, from the event's cwd or the file it writes\") callback.ls","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":103,"symbol":"test(\"a session at the repository top gets orient once, at its first tool use inside the project, and nothing for work elsewhere\") callback.hook.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":158,"symbol":"test(\"an event outside every project is ignored: no answer, nothing written, wherever the session started\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/registry.test.ts","line":101,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":103,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.inNotebooks","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":108,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.inErrors","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":112,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":116,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":137,"symbol":"test(\"the first tool use inside a nested project warms its instrument, once\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":154,"symbol":"test(\"an event outside every leaf of a registry spawns no git and writes nothing\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/stop-delivery.test.ts","line":84,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.pre","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":86,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":92,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":97,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.advisory","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":103,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":106,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.later","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":117,"symbol":"test(\"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\") callback.slow","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":119,"symbol":"test(\"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\") callback.fast","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":128,"symbol":"test(\"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\") callback.allowed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/telemetry.test.ts","line":231,"symbol":"test(\"telemetry adds no wait to a hook: the flush starts detached at a session start or a stop, and queuing is one appended line\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/version.test.ts","line":8,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/version.test.ts","line":109,"symbol":"test(\"the session start names the Coherence that runs and where it is, and warns when another copy the project reaches differs in version\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":12,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":227,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.quiet","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":231,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":237,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":239,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":255,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":260,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.ordinary","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":265,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":269,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.second","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":273,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":282,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":296,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":300,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":304,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":307,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":91,"symbol":"workOf","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":181,"symbol":"atBothSizes.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":510,"symbol":"test(\"in a project of two languages, an edit's check asks the language the last run graded the invariant in, with that run's whole file list\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":532,"symbol":"test(\"an edit is checked with GIT_LITERAL_PATHSPECS set as without it\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":554,"symbol":"test(\"a spec listing that comes back empty where the project holds specs falls back to the whole model and says so\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":582,"symbol":"test(\"an edit is checked against a spec changed at the same size with its modification time set back\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":604,"symbol":"test(\"an edit's chokepoint check never goes silent because a cache cannot be used\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":716,"symbol":"test(\"Stop reuses a complete vocabulary reading until a project file or record changes\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":745,"symbol":"test(\"an edit over torn or missing vocabulary buckets reads in full, says so, names nothing false and writes nothing derived from them\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":775,"symbol":"test(\"a write no hook saw is caught at the next edit, which reads in full as main does\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":800,"symbol":"test(\"the vocabulary tree key follows sparse checkout file membership\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":869,"symbol":"test(\"a checkout, a pull or a branch switch onto a clean tree moves the tree: the next edit and the next prompt read in full\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":892,"symbol":"test(\"an edit read through the kept vocabulary holds the term it makes recur for the stop, unsaid, as the full reading does\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":908,"symbol":"test(\"an edit whose kept vocabulary was left half-written reads in full and says so\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/practice.test.ts","line":316,"symbol":"test(\"PreToolUse delivers a fired practice whole once per version per session, then one line, and never blocks\") callback.fire.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":344,"symbol":"test(\"regulate names a practice that fired with no enactment since, advisory, and never refuses a subagent stop for it\") callback.fired","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":346,"symbol":"test(\"regulate names a practice that fired with no enactment since, advisory, and never refuses a subagent stop for it\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":351,"symbol":"test(\"regulate names a practice that fired with no enactment since, advisory, and never refuses a subagent stop for it\") callback.settled","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":420,"symbol":"test(\"a shell command that writes a file fires an edit trigger the way an edit tool does, and the text it writes counts as added\") callback.fire.result","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":3,"files":["src/cli.ts","src/enforcement/enforcement.test.ts","src/lifecycle/hook-serve.ts","src/lifecycle/hook-speed.test.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/lexicon-work.test.ts","src/lifecycle/mirrors.test.ts","src/lifecycle/monorepo.test.ts","src/lifecycle/registry.test.ts","src/lifecycle/stop-delivery.test.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/version.test.ts","src/lifecycle/vocabulary-signal.test.ts","src/lifecycle/work-meter.test.ts","src/spec/practice.test.ts"],"latency":242,"reason":"OUTSIDE_ROOT_EXIT is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/hook.ts:131 reads \"export const OUTSIDE_ROOT_EXIT = 78;\"); every reference in the project is inside the chokepoint; 3 test references","state":"invariant","enforces":["runHook"]},{"component":"src/lifecycle","name":"install keeps other hooks","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/cli.ts","line":459,"symbol":"hooksCommand.result","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/install.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/install.test.ts","line":15,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/install.test.ts","line":49,"symbol":"test(\"mergeHooks adds one Coherence entry per event, keeps everything else, and replaces its own entry on a second pass\") callback.first","class":"test","of":"protected","test":true},{"file":"src/lifecycle/install.test.ts","line":56,"symbol":"test(\"mergeHooks adds one Coherence entry per event, keeps everything else, and replaces its own entry on a second pass\") callback.second","class":"test","of":"protected","test":true},{"file":"src/lifecycle/install.test.ts","line":69,"symbol":"test(\"mergeHooks adds one Coherence entry per event, keeps everything else, and replaces its own entry on a second pass\") callback.crowded","class":"test","of":"protected","test":true},{"file":"src/lifecycle/install.test.ts","line":73,"symbol":"test(\"mergeHooks adds one Coherence entry per event, keeps everything else, and replaces its own entry on a second pass\") callback.merged","class":"test","of":"protected","test":true},{"file":"src/lifecycle/install.test.ts","line":78,"symbol":"test(\"mergeHooks adds one Coherence entry per event, keeps everything else, and replaces its own entry on a second pass\") callback.mixed","class":"test","of":"protected","test":true},{"file":"src/lifecycle/install.test.ts","line":85,"symbol":"test(\"install --host claude merges into .claude/settings.json without clobbering\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":101,"symbol":"test(\"install --host claude merges into .claude/settings.json without clobbering\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":107,"symbol":"test(\"install --host codex writes .codex/hooks.json in the same shape\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":221,"symbol":"test(\"uninstall removes only Coherence's commands and returns the settings to what they were before install\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":283,"symbol":"test(\"install keeps Coherence's regenerated state out of the project's git, and uninstall removes only the ignore file it wrote\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":295,"symbol":"test(\"install keeps Coherence's regenerated state out of the project's git, and uninstall removes only the ignore file it wrote\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":298,"symbol":"test(\"install keeps Coherence's regenerated state out of the project's git, and uninstall removes only the ignore file it wrote\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":312,"symbol":"test(\"install keeps Coherence's regenerated state out of the project's git, and uninstall removes only the ignore file it wrote\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":320,"symbol":"test(\"install keeps Coherence's regenerated state out of the project's git, and uninstall removes only the ignore file it wrote\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":332,"symbol":"test(\"the check names every drift from what install would write: missing, stale, and extra\") callback.clean","class":"test","of":"protected","test":true},{"file":"src/lifecycle/install.test.ts","line":459,"symbol":"test(\"a hook without Coherence installed tells the user once and the agent how to supply it, and is otherwise silent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":497,"symbol":"test(\"an installed package is located by its own cli before the project's bin, which a package manager may write as a shim node cannot run\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":522,"symbol":"test(\"a located Coherence answers, and refuses, as a direct command does\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":581,"symbol":"test(\"a checkout beside the project never runs, installed package or not; only COHERENCE_HOME names a checkout\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":618,"symbol":"test(\"hooks an earlier Coherence wrote, which look beside the project first, are named by the check and at the session start with the reinstall\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":630,"symbol":"test(\"hooks an earlier Coherence wrote, which look beside the project first, are named by the check and at the session start with the reinstall\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":640,"symbol":"test(\"a PreToolUse matcher that leaves out a tool that writes is named by the check and at the session start with the reinstall, and a wider one is not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.test.ts","line":655,"symbol":"test(\"a PreToolUse matcher that leaves out a tool that writes is named by the check and at the session start with the reinstall, and a wider one is not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/install.ts","line":309,"symbol":"install.merged","class":"inside","of":"protected","test":false}],"testReferences":7,"files":["src/cli.ts","src/lifecycle/install.test.ts","src/lifecycle/install.ts"],"latency":189,"reason":"mergeHooks is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/install.ts:275 reads \"export function mergeHooks(settings: Record\"); every reference in the project is inside the chokepoint; 7 test references","state":"invariant","enforces":["install"]},{"component":"src/lifecycle","name":"the update check adds no wait to a hook","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/cli.ts","line":75,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/cli.ts","line":538,"symbol":"versionCommand","class":"inside","of":"protected","test":false},{"file":"src/cli.ts","line":640,"symbol":"dispatch","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/version.test.ts","line":18,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/version.test.ts","line":177,"symbol":"test(\"a failed fetch keeps the last answer, and version says when the registry last answered and when a check got none\") callback.first","class":"test","of":"protected","test":true},{"file":"src/lifecycle/version.test.ts","line":180,"symbol":"test(\"a failed fetch keeps the last answer, and version says when the registry last answered and when a check got none\") callback.failed","class":"test","of":"protected","test":true}],"testReferences":3,"files":["src/cli.ts","src/lifecycle/version.test.ts","src/lifecycle/version.ts"],"latency":174,"reason":"refreshLatest is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/version.ts:338 reads \"export async function refreshLatest(env: Env = process.env, \"); every reference in the project is inside the chokepoint; 3 test references","state":"invariant","enforces":["versionCommand"]},{"component":"src/lifecycle","name":"cursor advances after the print","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/journal/feed.ts","line":56,"symbol":"cursorFile","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":60,"symbol":"readCursor.file","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":72,"symbol":"writeCursor.file","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":74,"symbol":"writeCursor","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":88,"symbol":"openFeed","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":93,"symbol":"openFeed","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":93,"symbol":"openFeed","class":"inside","of":"protected","test":false},{"file":"src/journal/feed.ts","line":111,"symbol":"peerFeed","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":112,"symbol":"peerFeed.none","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":113,"symbol":"peerFeed","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":114,"symbol":"peerFeed.since","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":116,"symbol":"peerFeed","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":127,"symbol":"peerFeed.fresh.all.filter() callback","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":131,"symbol":"peerFeed.all.some() callback","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":132,"symbol":"peerFeed.commit","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":132,"symbol":"peerFeed.commit","class":"inside","of":"protected","test":false},{"file":"src/journal/feed.ts","line":133,"symbol":"peerFeed.first","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":139,"symbol":"peerFeed.commit","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":139,"symbol":"peerFeed.commit","class":"inside","of":"protected","test":false},{"file":"src/journal/feed.ts","line":143,"symbol":"seenFile","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":158,"symbol":"writeSeen","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":177,"symbol":"returnFile","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":181,"symbol":"startFile","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":188,"symbol":"markChildStart","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":207,"symbol":"leaveReturn","class":"inside","of":"chokepoint","test":false},{"file":"src/journal/feed.ts","line":219,"symbol":"returnFeed","class":"inside","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook.test.ts","line":652,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":680,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":705,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":709,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":710,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":715,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":719,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":750,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":754,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":759,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":765,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":770,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.ts","line":93,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":93,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":93,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":93,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":93,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":936,"symbol":"feedContext.returns","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.ts","line":937,"symbol":"feedContext.peers","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.ts","line":1358,"symbol":"runHook.answer.commit","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.ts","line":1392,"symbol":"runHook.respond","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.ts","line":1394,"symbol":"runHook.respond","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.ts","line":1551,"symbol":"runHook.respond","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/work-meter.test.ts","line":38,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":38,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":38,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":685,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":685,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":686,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":689,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback.a","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":695,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback.b","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":698,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":702,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":705,"symbol":"test(\"the peer feed shows every record a peer appended, through a cleared cache and memo, a file that arrived from outside, and a peer who reads between ap...) callback","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":2,"files":["src/journal/feed.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/work-meter.test.ts"],"latency":198,"reason":"writeCursor is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/feed.ts:71 reads \"export function writeCursor(root: string, session: string, c\"); every reference in the project is inside the chokepoint; 2 test references","state":"invariant","enforces":["src/journal/feed.ts"]},{"component":"src/lifecycle","name":"a hook voice file stays inside the root","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/lifecycle/hook.ts","line":1154,"symbol":"voiceFile.name","class":"inside","of":"protected","test":false},{"file":"src/lifecycle/hook.ts","line":1175,"symbol":"readHookVoice.override","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.ts","line":1176,"symbol":"readHookVoice.append","class":"chokepoint-reference","of":"chokepoint","test":false}],"testReferences":0,"files":["src/lifecycle/hook.ts"],"latency":165,"reason":"HOOK_VOICE_DIR is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/hook.ts:1140 reads \"export const HOOK_VOICE_DIR = join(\".coherence\", \"hooks\");\"); every reference in the project is inside the chokepoint","state":"invariant","enforces":["voiceFile"]},{"component":"src/lifecycle","name":"the corpus is read only through readCorpus","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/adapters/ignore-files.test.ts","line":18,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/ignore-files.test.ts","line":74,"symbol":"test(\"the ignore list names a file by its path: every walk, the vocabulary corpus, an edit's reading and coverage leave it out, and a file elsewhere by the...) callback.corpus","class":"test","of":"protected","test":true},{"file":"src/adapters/project-files.test.ts","line":24,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/project-files.test.ts","line":143,"symbol":"test(\"only the project's own files are ever evidence: a nested checkout and an ignored path are no bypass, no vocabulary, and no mass\") callback.corpus","class":"test","of":"protected","test":true},{"file":"src/adapters/walks.test.ts","line":24,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/adapters/walks.test.ts","line":98,"symbol":"test(\"every walk reads what the one rule leaves in: a folder is left out only by a named rule, never by its name alone\") callback.corpus","class":"test","of":"protected","test":true},{"file":"src/lifecycle/check.ts","line":344,"symbol":"readCorpus","class":"inside","of":"protected","test":false},{"file":"src/lifecycle/check.ts","line":777,"symbol":"runCheck","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-coverage.ts","line":46,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/lexicon-coverage.ts","line":405,"symbol":"liveUses.corpus","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/lexicon-coverage.ts","line":543,"symbol":"lexiconReading.corpus","class":"chokepoint-reference","of":"chokepoint","test":false}],"testReferences":6,"files":["src/adapters/ignore-files.test.ts","src/adapters/project-files.test.ts","src/adapters/walks.test.ts","src/lifecycle/check.ts","src/lifecycle/lexicon-coverage.ts"],"latency":178,"reason":"collectFiles is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/check.ts:290 reads \"export async function collectFiles(options: CheckOptions): P\"); every reference in the project is inside the chokepoint; 6 test references","state":"invariant","enforces":["readCorpus"]},{"component":"src/lifecycle","name":"only runHook opens a work scope","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/cli.ts","line":54,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/cli.ts","line":278,"symbol":"hookCommand.result","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/enforcement.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":472,"symbol":"test(\"PostToolUse on a file-writing tool re-checks the invariants that may involve the file and prints the bypass with the two options; Stop carries the de...) callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":484,"symbol":"test(\"PostToolUse on a file-writing tool re-checks the invariants that may involve the file and prints the bypass with the two options; Stop carries the de...) callback.reading","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":486,"symbol":"test(\"PostToolUse on a file-writing tool re-checks the invariants that may involve the file and prints the bypass with the two options; Stop carries the de...) callback.unrelated","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-serve.ts","line":36,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook-serve.ts","line":119,"symbol":"hookServer.one.result","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook-speed.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook-speed.test.ts","line":68,"symbol":"test(\"a stop starts the snapshot detached, with a fingerprint that moves only with the patch, and reports the newest one already recorded\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":70,"symbol":"test(\"a stop starts the snapshot detached, with a fingerprint that moves only with the patch, and reports the newest one already recorded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":72,"symbol":"test(\"a stop starts the snapshot detached, with a fingerprint that moves only with the patch, and reports the newest one already recorded\") callback.edited","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":88,"symbol":"test(\"a session start and every prompt warm the instrument without waiting for it, and no other event does\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":185,"symbol":"test(\"a tool call's hooks spawn git a fixed number of times, whatever the number of components and practices\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":207,"symbol":"test(\"the vocabulary coverage reading runs at a tool hook only after a write, and at a prompt only when the tree moved\") callback.hook","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook.test.ts","line":107,"symbol":"test(\"SessionStart and SubagentStart inject both lexicons and the instruction as additionalContext\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":130,"symbol":"test(\"Coherence's own start hooks name its source-tree journal command\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":149,"symbol":"test(\"a session start in a project that adopted an earlier release writes the attributes file its records merge by and brings the earlier ignore file up so...) callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":161,"symbol":"test(\"UserPromptSubmit and PostToolUse print nothing\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":167,"symbol":"test(\"Stop and SubagentStop with a clean working tree are silent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":168,"symbol":"test(\"Stop and SubagentStop with a clean working tree are silent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":176,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":184,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":190,"symbol":"test(\"with defects in changed files: Stop reports and exits 0; SubagentStop refuses with exit 2 and the reason on stderr\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":200,"symbol":"test(\"an unknown noun in a changed file is advisory: Stop reports it and SubagentStop never refuses on it\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":216,"symbol":"test(\"in an adopter, Coherence's rejected names in the project's own code, prose and specs never refuse a subagent stop, and the stop names none of them\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":232,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.refused","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":235,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.excused","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":240,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.other","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":246,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.problem","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":249,"symbol":"test(\"an unable record from the session turns the debt it names advisory: SubagentStop reports it and exits 0, and another session is still refused\") callback.allowed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":268,"symbol":"test(\"changedFiles reports a git failure instead of answering a clean tree; outside git the answer is no files\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":272,"symbol":"test(\"changedFiles reports a git failure instead of answering a clean tree; outside git the answer is no files\") callback.subagent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":291,"symbol":"test(\"an unacknowledged escalation heads the start output; an acknowledged one does not\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":300,"symbol":"test(\"an unacknowledged escalation heads the start output; an acknowledged one does not\") callback.after","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":315,"symbol":"test(\"an open escalation that cites a decision and a work order names each by id, kind and subject in the start output\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":337,"symbol":"test(\"the start injection stays under the budget with escalations present: the vocabulary decays from its least recently named concept, to names and then t...) callback.context","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":354,"symbol":"test(\"the start injection stays under the budget with escalations present: the vocabulary decays from its least recently named concept, to names and then t...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":367,"symbol":"test(\"the start injection stays under the budget with escalations present: the vocabulary decays from its least recently named concept, to names and then t...) callback.light","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":408,"symbol":"test(\"the hook refuses a cwd from stdin that is not inside the project root it was installed for\") callback.ok","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":413,"symbol":"test(\"the hook refuses a cwd from stdin that is not inside the project root it was installed for\") callback.out","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":446,"symbol":"test(\"the Stop snapshot reaches the instrument through enforcement's one door, in production as in a test\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":457,"symbol":"test(\"the Stop snapshot reaches the instrument through enforcement's one door, in production as in a test\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":508,"symbol":"test(\"orient lists open requirements and regulate reports them; only spec problems refuse a subagent stop\") callback.hook","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":545,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.silent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":549,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.open","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":552,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":555,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.active","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":559,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.other","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":563,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":571,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback.several","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":576,"symbol":"test(\"orient prints the active order a session owns with the boundary rule, nudges an open one, and regulate reminds that work close ends it\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":586,"symbol":"test(\"the peer feed injects a peer's decisions and escalations and no other kind\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":597,"symbol":"test(\"the peer feed injects a peer's decisions and escalations and no other kind\") callback.feed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":615,"symbol":"test(\"a subagent's start names its own session and its coordinator's, and says never to write under the coordinator's\") callback.child","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":619,"symbol":"test(\"a subagent's start names its own session and its coordinator's, and says never to write under the coordinator's\") callback.main","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":631,"symbol":"test(\"the main thread's feed counts a record of its own session under another agent's name as a peer's\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":634,"symbol":"test(\"the main thread's feed counts a record of its own session under another agent's name as a peer's\") callback.tool","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":649,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":650,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":655,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":658,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback.unprinted","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":660,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":668,"symbol":"test(\"a subagent that stops returns every record it made to its coordinator's next boundary, once, uncapped\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":678,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":681,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":689,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":703,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":706,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback.tool","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":716,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":717,"symbol":"test(\"the peer feed injects subjects of other sessions' records since the cursor, capped, never full records\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":747,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":749,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":757,"symbol":"test(\"the feed cursor advances only after the feed is printed: rendering moves nothing, and the CLI commits only once its stdout write succeeded\") callback.rendered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":784,"symbol":"gapStarter.start.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":863,"symbol":"test(\"the session's stop starts one background reading of the tree it leaves when the recorded one no longer describes it, and returns without waiting; a s...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":869,"symbol":"test(\"the session's stop starts one background reading of the tree it leaves when the recorded one no longer describes it, and returns without waiting; a s...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":871,"symbol":"test(\"the session's stop starts one background reading of the tree it leaves when the recorded one no longer describes it, and returns without waiting; a s...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":882,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback.opened","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":884,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":888,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":894,"symbol":"test(\"regulate names the gaps a session touched, a changed handler file and an untrusted entrance it declared, and never refuses a subagent stop for them\") callback.sub","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":941,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback.opened","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":943,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":946,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback.message","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":949,"symbol":"test(\"regulate names the undeclared entrances in the files a session changed, by file, and never refuses a subagent stop for them\") callback.sub","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":976,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.plain","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":979,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":980,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":983,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":986,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.silent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":990,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":992,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":994,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.fed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":998,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.overridden","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1005,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1008,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1013,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.refused","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1019,"symbol":"test(\"a project's hook voice composes over what each event says: an override replaces it, an empty one silences it, an append follows it, an event with not...) callback.reported","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1037,"symbol":"test(\"a hook voice file whose real path leaves the project root is named as not read and never followed\") callback.linked","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1044,"symbol":"test(\"a hook voice file whose real path leaves the project root is named as not read and never followed\") callback.folder","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.test.ts","line":1054,"symbol":"test(\"a hook voice file whose real path leaves the project root is named as not read and never followed\") callback.inside","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook.ts","line":75,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":1273,"symbol":"runHook.work","class":"inside","of":"protected","test":false},{"file":"src/lifecycle/lexicon-work.test.ts","line":417,"symbol":"test(\"lexicon lifecycle uses child identities and installed roots, and advances changed contexts only after delivery\") callback.runHook","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/mirrors.test.ts","line":7,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/mirrors.test.ts","line":79,"symbol":"edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/monorepo.test.ts","line":78,"symbol":"test(\"a hook at the repository top answers for the one project nested below it, from the event's cwd or the file it writes\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":81,"symbol":"test(\"a hook at the repository top answers for the one project nested below it, from the event's cwd or the file it writes\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":87,"symbol":"test(\"a hook at the repository top answers for the one project nested below it, from the event's cwd or the file it writes\") callback.ls","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":103,"symbol":"test(\"a session at the repository top gets orient once, at its first tool use inside the project, and nothing for work elsewhere\") callback.hook.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":158,"symbol":"test(\"an event outside every project is ignored: no answer, nothing written, wherever the session started\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/registry.test.ts","line":101,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":103,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.inNotebooks","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":108,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.inErrors","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":112,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":116,"symbol":"test(\"with a registry, events from the repository top route to the leaf with the longest listed prefix, and anything in no leaf is ignored\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":137,"symbol":"test(\"the first tool use inside a nested project warms its instrument, once\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/registry.test.ts","line":154,"symbol":"test(\"an event outside every leaf of a registry spawns no git and writes nothing\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/stop-delivery.test.ts","line":84,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.pre","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":86,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":92,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":97,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.advisory","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":103,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":106,"symbol":"test(\"a stop says each line once, blocks once for a practice owed, and carries the rest into the next prompt\") callback.later","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":117,"symbol":"test(\"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\") callback.slow","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":119,"symbol":"test(\"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\") callback.fast","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/stop-delivery.test.ts","line":128,"symbol":"test(\"a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it\") callback.allowed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/telemetry.test.ts","line":231,"symbol":"test(\"telemetry adds no wait to a hook: the flush starts detached at a session start or a stop, and queuing is one appended line\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/version.test.ts","line":8,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/version.test.ts","line":109,"symbol":"test(\"the session start names the Coherence that runs and where it is, and warns when another copy the project reaches differs in version\") callback.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":12,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":227,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.quiet","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":231,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":237,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":239,"symbol":"test(\"no hook injection carries a total: orient names the ranked terms or says nothing\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":255,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":260,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.ordinary","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":265,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":269,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.second","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":273,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":282,"symbol":"test(\"an edit is silent on the terms it makes recur: regulate names the session's together at the stop, once, with the declare-or-alias command\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":296,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":300,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.edit","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":304,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.prompt","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/vocabulary-signal.test.ts","line":307,"symbol":"test(\"a term an edit held reaches the next prompt when no stop named it, once\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":24,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":91,"symbol":"workOf","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":181,"symbol":"atBothSizes.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":349,"symbol":"phraseComparisons.scope","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":402,"symbol":"test(\"every way of reading a file's bytes is weighed by them, and a spawn through a shell or a recursive tool is project-sized\") callback.scope","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":467,"symbol":"test(\"every spawn is counted at runtime, whatever route reached child_process\") callback.scope","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":510,"symbol":"test(\"in a project of two languages, an edit's check asks the language the last run graded the invariant in, with that run's whole file list\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":532,"symbol":"test(\"an edit is checked with GIT_LITERAL_PATHSPECS set as without it\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":554,"symbol":"test(\"a spec listing that comes back empty where the project holds specs falls back to the whole model and says so\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":582,"symbol":"test(\"an edit is checked against a spec changed at the same size with its modification time set back\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":604,"symbol":"test(\"an edit's chokepoint check never goes silent because a cache cannot be used\") callback.answered","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":716,"symbol":"test(\"Stop reuses a complete vocabulary reading until a project file or record changes\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":745,"symbol":"test(\"an edit over torn or missing vocabulary buckets reads in full, says so, names nothing false and writes nothing derived from them\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":775,"symbol":"test(\"a write no hook saw is caught at the next edit, which reads in full as main does\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":800,"symbol":"test(\"the vocabulary tree key follows sparse checkout file membership\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":804,"symbol":"test(\"the vocabulary tree key follows sparse checkout file membership\") callback.read.scope","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":869,"symbol":"test(\"a checkout, a pull or a branch switch onto a clean tree moves the tree: the next edit and the next prompt read in full\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":892,"symbol":"test(\"an edit read through the kept vocabulary holds the term it makes recur for the stop, unsaid, as the full reading does\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":908,"symbol":"test(\"an edit whose kept vocabulary was left half-written reads in full and says so\") callback.start","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":927,"symbol":"test(\"a work scope opened inside another adds its counts to the outer one\") callback.outer","class":"test","of":"protected","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":929,"symbol":"test(\"a work scope opened inside another adds its counts to the outer one\") callback.inner","class":"test","of":"protected","test":true},{"file":"src/readings/scope/live.test.ts","line":16,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/readings/scope/live.test.ts","line":299,"symbol":"test(\"every file the spec model reads by name refreshes the live reading: each spec and practice file it read for a project with components and a practice,...) callback.scope","class":"test","of":"protected","test":true},{"file":"src/spec/dead-triggers.test.ts","line":18,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/spec/dead-triggers.test.ts","line":108,"symbol":"test(\"the dead-trigger check lists only what its triggers name, so a project ten times larger costs it nothing more\") callback.output.scope","class":"test","of":"protected","test":true},{"file":"src/spec/dead-triggers.test.ts","line":135,"symbol":"test(\"a dead trigger in a leaf is looked for outside it as narrowly, so the repository's size costs the check nothing\") callback.measured.scope","class":"test","of":"protected","test":true},{"file":"src/spec/practice.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/practice.test.ts","line":316,"symbol":"test(\"PreToolUse delivers a fired practice whole once per version per session, then one line, and never blocks\") callback.fire.result","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":344,"symbol":"test(\"regulate names a practice that fired with no enactment since, advisory, and never refuses a subagent stop for it\") callback.fired","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":346,"symbol":"test(\"regulate names a practice that fired with no enactment since, advisory, and never refuses a subagent stop for it\") callback.stop","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":351,"symbol":"test(\"regulate names a practice that fired with no enactment since, advisory, and never refuses a subagent stop for it\") callback.settled","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":420,"symbol":"test(\"a shell command that writes a file fires an edit trigger the way an edit tool does, and the text it writes counts as added\") callback.fire.result","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":12,"files":["src/cli.ts","src/enforcement/enforcement.test.ts","src/lifecycle/hook-serve.ts","src/lifecycle/hook-speed.test.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/lexicon-work.test.ts","src/lifecycle/mirrors.test.ts","src/lifecycle/monorepo.test.ts","src/lifecycle/registry.test.ts","src/lifecycle/stop-delivery.test.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/version.test.ts","src/lifecycle/vocabulary-signal.test.ts","src/lifecycle/work-meter.test.ts","src/lifecycle/work-meter.ts","src/readings/scope/live.test.ts","src/spec/dead-triggers.test.ts","src/spec/practice.test.ts"],"latency":236,"reason":"openWork is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/work-meter.ts:76 reads \"export function openWork(): WorkScope {\"); every reference in the project is inside the chokepoint; 12 test references","state":"invariant","enforces":["runHook"]},{"component":"src/lifecycle","name":"telemetry is sent only on opt-in","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/lifecycle/telemetry-cli.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/telemetry-cli.ts","line":88,"symbol":"telemetryCommand","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/telemetry.test.ts","line":22,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/telemetry.test.ts","line":107,"symbol":"test(\"nothing is queued or sent unless the user opted in, and a project's refusal or the environment always wins\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":127,"symbol":"test(\"nothing is queued or sent unless the user opted in, and a project's refusal or the environment always wins\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":131,"symbol":"test(\"nothing is queued or sent unless the user opted in, and a project's refusal or the environment always wins\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":166,"symbol":"test(\"every telemetry event carries only the fields its schema allows, and a field outside it is refused\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":248,"symbol":"test(\"a flush sends the queue in one POST to the batch endpoint and drops it, sent or not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":255,"symbol":"test(\"a flush sends the queue in one POST to the batch endpoint and drops it, sent or not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":263,"symbol":"test(\"a flush sends the queue in one POST to the batch endpoint and drops it, sent or not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.ts","line":564,"symbol":"flushQueue","class":"inside","of":"protected","test":false}],"testReferences":0,"files":["src/lifecycle/telemetry-cli.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/telemetry.ts"],"latency":179,"reason":"FETCH_SENDER is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/telemetry.ts:544 reads \"export const FETCH_SENDER: Sender = async (url, body, timeou\"); every reference in the project is inside the chokepoint","state":"invariant","enforces":["flushQueue"]},{"component":"src/lifecycle","name":"telemetry adds no wait to a hook","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/cli.ts","line":71,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/cli.ts","line":632,"symbol":"dispatch","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/telemetry-cli.ts","line":13,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/lifecycle/telemetry-cli.ts","line":88,"symbol":"telemetryCommand","class":"inside","of":"protected","test":false},{"file":"src/lifecycle/telemetry.test.ts","line":22,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/lifecycle/telemetry.test.ts","line":40,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/telemetry.test.ts","line":107,"symbol":"test(\"nothing is queued or sent unless the user opted in, and a project's refusal or the environment always wins\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":127,"symbol":"test(\"nothing is queued or sent unless the user opted in, and a project's refusal or the environment always wins\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":131,"symbol":"test(\"nothing is queued or sent unless the user opted in, and a project's refusal or the environment always wins\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":166,"symbol":"test(\"every telemetry event carries only the fields its schema allows, and a field outside it is refused\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":248,"symbol":"test(\"a flush sends the queue in one POST to the batch endpoint and drops it, sent or not\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":255,"symbol":"test(\"a flush sends the queue in one POST to the batch endpoint and drops it, sent or not\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":263,"symbol":"test(\"a flush sends the queue in one POST to the batch endpoint and drops it, sent or not\") callback","class":"test","of":"protected","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":299,"symbol":"test(\"telemetry on, off, status, show and reset-id say what they did, and show prints the queue as it would be sent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":302,"symbol":"test(\"telemetry on, off, status, show and reset-id say what they did, and show prints the queue as it would be sent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":308,"symbol":"test(\"telemetry on, off, status, show and reset-id say what they did, and show prints the queue as it would be sent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":310,"symbol":"test(\"telemetry on, off, status, show and reset-id say what they did, and show prints the queue as it would be sent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.test.ts","line":313,"symbol":"test(\"telemetry on, off, status, show and reset-id say what they did, and show prints the queue as it would be sent\") callback","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":8,"files":["src/cli.ts","src/lifecycle/telemetry-cli.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/telemetry.ts"],"latency":171,"reason":"flushQueue is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/telemetry.ts:564 reads \"export async function flushQueue(env: Env = process.env, sen\"); every reference in the project is inside the chokepoint; 8 test references","state":"invariant","enforces":["telemetryCommand"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":85,"symbol":"KeptReader","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":215,"symbol":"treeReaderOf.store","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":278,"symbol":"warmParses","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":304,"symbol":"parserNotice.misreads","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":307,"symbol":"parserNotice.unreads","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":324,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":534,"symbol":"readerOver","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":547,"symbol":"readerOver.read","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":554,"symbol":"readerOver.read","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":647,"symbol":"ParseStore.stores","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":659,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":660,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":661,"symbol":"ParseStore.of.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":668,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":668,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":670,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":710,"symbol":"ParseStore.discard","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":754,"symbol":"ParseStore.sweep.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":792,"symbol":"ParseStore.writeAudit.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":805,"symbol":"ParseStore.writeNote.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":817,"symbol":"ParseStore.notes.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":834,"symbol":"ParseStore.audits.parses","class":"inside","of":"protected","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":1968,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:855 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["ParseStore in src/plugins/syntax-trees.ts"]},{"component":"src/readings/scope","name":"fixed shell","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/enforcement/from.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/from.test.ts","line":176,"symbol":"test(\"Scope and the agent query show which references governed: the from: line with its exempt count on the enforcement, each exempt site as exempt, and th...) callback.state","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/lexicon-work.test.ts","line":505,"symbol":"test(\"Scope and the fixed lexicon query expose the same live sense evidence and escape source text\") callback.loadState","class":"test","of":"protected","test":true},{"file":"src/readings/scope/build.ts","line":460,"symbol":"scopeState.loaded","class":"inside","of":"protected","test":false},{"file":"src/readings/scope/build.ts","line":514,"symbol":"buildScopePage.state","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/scope/check.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/check.test.ts","line":373,"symbol":"test(\"the shell's bytes are independent of project content; the same state in renders the same page out\") callback.same.first","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/check.test.ts","line":374,"symbol":"test(\"the shell's bytes are independent of project content; the same state in renders the same page out\") callback.same.second","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/check.test.ts","line":396,"symbol":"test(\"the shell's bytes are independent of project content; the same state in renders the same page out\") callback.other","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/live.test.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/live.test.ts","line":243,"symbol":"test(\"the first load stays flat as the journal and the runs grow, every derived verdict is unchanged, and history loads every record left out by cursor, on...) callback.whole","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/live.ts","line":43,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/readings/scope/live.ts","line":175,"symbol":"LiveReading.ensure..state","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/scope/live.ts","line":262,"symbol":"LiveReading.refresh.state","class":"chokepoint-reference","of":"chokepoint","test":false}],"testReferences":1,"files":["src/enforcement/from.test.ts","src/lifecycle/lexicon-work.test.ts","src/readings/scope/build.ts","src/readings/scope/check.test.ts","src/readings/scope/live.test.ts","src/readings/scope/live.ts"],"latency":161,"reason":"loadState is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/readings/scope/build.ts:247 reads \"export async function loadState(options: BuildOptions): Prom\"); every reference in the project is inside the chokepoint; 1 test reference","state":"invariant","enforces":["scopeState"]},{"component":"src/scaffold","name":"every slot printed","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/scaffold/boundaries.ts","line":38,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/boundaries.ts","line":159,"symbol":"renderDraft.bullet","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":120,"symbol":"invariantVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":48,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/control.ts","line":246,"symbol":"proposeClosures","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.test.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/scaffold/scaffold.test.ts","line":83,"symbol":"test(\"scaffold invariant prints every slot and only the applicable checklist shapes\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":100,"symbol":"test(\"scaffold invariant prints every slot and only the applicable checklist shapes\") callback.totality","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":105,"symbol":"test(\"scaffold invariant prints every slot and only the applicable checklist shapes\") callback.crossed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":110,"symbol":"test(\"scaffold invariant prints every slot and only the applicable checklist shapes\") callback.assert.throws() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":167,"symbol":"test(\"an unfilled slot is one of the forms the scaffold prints, not any prose in angle brackets\") callback.printed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.ts","line":149,"symbol":"renderInvariant","class":"inside","of":"protected","test":false},{"file":"src/scaffold/scaffold.ts","line":153,"symbol":"renderInvariant.value","class":"inside","of":"protected","test":false},{"file":"src/scaffold/scaffold.ts","line":160,"symbol":"renderInvariant","class":"inside","of":"protected","test":false},{"file":"src/scaffold/scaffold.ts","line":164,"symbol":"renderInvariant.value","class":"inside","of":"protected","test":false},{"file":"src/scaffold/scaffold.ts","line":172,"symbol":"renderInvariant","class":"inside","of":"protected","test":false}],"testReferences":0,"files":["src/scaffold/boundaries.ts","src/scaffold/cli.ts","src/scaffold/control.ts","src/scaffold/scaffold.test.ts","src/scaffold/scaffold.ts"],"latency":1964,"reason":"PLACEHOLDERS is visibility-choked, enforced by the compiler: not visible outside its module (src/scaffold/scaffold.ts:119 declares PLACEHOLDERS without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["renderInvariant"]},{"component":"src/scaffold","name":"a component lives under its project","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"plugins/python/tach-boundaries.ts","line":12,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/python/tach-boundaries.ts","line":79,"symbol":"readTach","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/python/tach-boundaries.ts","line":131,"symbol":"readTach","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/api.ts","line":58,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"re-export"},{"file":"src/scaffold/boundaries.ts","line":38,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/boundaries.ts","line":38,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/boundaries.ts","line":38,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/boundaries.ts","line":38,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/boundaries.ts","line":38,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/boundaries.ts","line":151,"symbol":"renderDraft.specPath","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/boundaries.ts","line":152,"symbol":"renderDraft.title","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/boundaries.ts","line":159,"symbol":"renderDraft.bullet","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/boundaries.ts","line":212,"symbol":"writeDrafts.dir","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/boundaries.ts","line":213,"symbol":"writeDrafts.existing","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/boundaries.ts","line":218,"symbol":"writeDrafts.path","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":57,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":70,"symbol":"usage","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":78,"symbol":"componentVerb.result","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":103,"symbol":"invariantVerb.form","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":104,"symbol":"invariantVerb.dir","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":106,"symbol":"invariantVerb.specs","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":107,"symbol":"invariantVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":110,"symbol":"invariantVerb.crossing","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":120,"symbol":"invariantVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":125,"symbol":"invariantVerb.finish","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":133,"symbol":"invariantVerb.finish.guidance","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":149,"symbol":"invariantVerb.then() callback","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":197,"symbol":"controlModel","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":218,"symbol":"askedOf","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":220,"symbol":"askedOf","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":237,"symbol":"chosen","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":239,"symbol":"chosen","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":241,"symbol":"chosen","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":242,"symbol":"chosen","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":307,"symbol":"controlVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":334,"symbol":"entrancesVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":337,"symbol":"entrancesVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":346,"symbol":"scaffoldFailure","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":358,"symbol":"practiceVerb.dir","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":359,"symbol":"practiceVerb.specs","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":361,"symbol":"practiceVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":362,"symbol":"practiceVerb.bullet","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":365,"symbol":"practiceVerb.path","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":366,"symbol":"practiceVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":48,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/control.ts","line":48,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/control.ts","line":48,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/control.ts","line":246,"symbol":"proposeClosures","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":387,"symbol":"insertEntranceLine","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":394,"symbol":"insertEntranceLine","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":398,"symbol":"insertEntranceLine","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":414,"symbol":"nameCoveredEntrance","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":423,"symbol":"nameCoveredEntrance","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":424,"symbol":"nameCoveredEntrance","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":445,"symbol":"writeClosure","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/control.ts","line":448,"symbol":"writeClosure","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/import.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/import.ts","line":25,"symbol":"importVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/import.ts","line":27,"symbol":"importVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/import.ts","line":29,"symbol":"importVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/import.ts","line":31,"symbol":"importVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/import.ts","line":35,"symbol":"importVerb","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/scaffold/scaffold.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/scaffold/scaffold.test.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/scaffold/scaffold.test.ts","line":83,"symbol":"test(\"scaffold invariant prints every slot and only the applicable checklist shapes\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":100,"symbol":"test(\"scaffold invariant prints every slot and only the applicable checklist shapes\") callback.totality","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":105,"symbol":"test(\"scaffold invariant prints every slot and only the applicable checklist shapes\") callback.crossed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":110,"symbol":"test(\"scaffold invariant prints every slot and only the applicable checklist shapes\") callback.assert.throws() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":167,"symbol":"test(\"an unfilled slot is one of the forms the scaffold prints, not any prose in angle brackets\") callback.printed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":212,"symbol":"test(\"scaffold confines a component folder to the project root\") callback.assert.throws(`${folder} reaches above the project root`) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":221,"symbol":"test(\"scaffold confines a component folder to the project root\") callback.assert.throws(`componentDir is the one door and it refuses ${folder}`) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":223,"symbol":"test(\"scaffold confines a component folder to the project root\") callback.inside","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":225,"symbol":"test(\"scaffold confines a component folder to the project root\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":235,"symbol":"test(\"the entry component is named for the project, not the checkout folder\") callback.specFileName","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.ts","line":70,"symbol":"confineToRoot","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":81,"symbol":"componentDir","class":"inside","of":"protected","test":false},{"file":"src/scaffold/scaffold.ts","line":85,"symbol":"scaffoldComponent","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":86,"symbol":"scaffoldComponent","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":87,"symbol":"scaffoldComponent.dir","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":88,"symbol":"scaffoldComponent.existing","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":89,"symbol":"scaffoldComponent","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":90,"symbol":"scaffoldComponent.file","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":93,"symbol":"scaffoldComponent.text","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":106,"symbol":"InvariantOptions.form","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":134,"symbol":"renderInvariant","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":134,"symbol":"renderInvariant","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":136,"symbol":"renderInvariant","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":140,"symbol":"renderInvariant","class":"inside","of":"chokepoint","test":false},{"file":"src/scaffold/scaffold.ts","line":184,"symbol":"parseCrossing","class":"inside","of":"chokepoint","test":false}],"testReferences":0,"files":["plugins/python/tach-boundaries.ts","src/plugins/api.ts","src/scaffold/boundaries.ts","src/scaffold/cli.ts","src/scaffold/control.ts","src/scaffold/import.ts","src/scaffold/scaffold.test.ts","src/scaffold/scaffold.ts"],"latency":829,"reason":"confineToRoot is visibility-choked, enforced by the compiler: not visible outside its module (src/scaffold/scaffold.ts:66 declares confineToRoot without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["src/scaffold/scaffold.ts"]},{"component":"src/spec","name":"retired sections refused","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/spec/grammar.ts","line":338,"symbol":"retiredSection","class":"inside","of":"protected","test":false},{"file":"src/spec/grammar.ts","line":437,"symbol":"parseSpec.lines.forEach() callback.retired","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/spec/spec.test.ts","line":14,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/spec/spec.test.ts","line":237,"symbol":"test(\"every retired section is refused by name with its replacement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":238,"symbol":"test(\"every retired section is refused by name with its replacement\") callback","class":"test","of":"protected","test":true}],"testReferences":3,"files":["src/spec/grammar.ts","src/spec/spec.test.ts"],"latency":172,"reason":"RETIRED_SECTIONS is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/spec/grammar.ts:62 reads \"export const RETIRED_SECTIONS: readonly RetiredSection[] = (\"); every reference in the project is inside the chokepoint; 3 test references","state":"invariant","enforces":["retiredSection"]},{"component":"src/spec","name":"requirement until complete","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sites":[{"file":"src/adapters/ignore-files.test.ts","line":22,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/ignore-files.test.ts","line":94,"symbol":"test(\"an ignore entry that names no file or folder is a spec problem; a folder by name or path, a file by path, and a folder git ignores are not\") callback.ignoreProblems","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/ignore-files.test.ts","line":107,"symbol":"test(\"an ignore entry git ignores is no spec problem though nothing it names is there: dist and build absent in a single-package repo, and dist only in a m...) callback.ignoreProblems","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/economy/closure.ts","line":43,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/economy/closure.ts","line":160,"symbol":"predictClosure.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/economy/mass.ts","line":29,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/economy/mass.ts","line":136,"symbol":"computeMass.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/cli.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/enforcement/cli.ts","line":228,"symbol":"runCommand.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/cli.ts","line":380,"symbol":"refuteCommand.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/enforcement.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":21,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":319,"symbol":"test(\"the state derivation without a run: a chokepoint bullet lacks refutation; with a run: automatic refutation satisfies it, a fail is a structural defec...) callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":321,"symbol":"test(\"the state derivation without a run: a chokepoint bullet lacks refutation; with a run: automatic refutation satisfies it, a fail is a structural defec...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":322,"symbol":"test(\"the state derivation without a run: a chokepoint bullet lacks refutation; with a run: automatic refutation satisfies it, a fail is a structural defec...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":324,"symbol":"test(\"the state derivation without a run: a chokepoint bullet lacks refutation; with a run: automatic refutation satisfies it, a fail is a structural defec...) callback.passing","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":328,"symbol":"test(\"the state derivation without a run: a chokepoint bullet lacks refutation; with a run: automatic refutation satisfies it, a fail is a structural defec...) callback.failing","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":331,"symbol":"test(\"the state derivation without a run: a chokepoint bullet lacks refutation; with a run: automatic refutation satisfies it, a fail is a structural defec...) callback.vacuous","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":373,"symbol":"test(\"a run appends one record, never rewrites; spec --check reads the run; the status view derives the latest verdict and keeps a skipped one dated\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":387,"symbol":"test(\"a run appends one record, never rewrites; spec --check reads the run; the status view derives the latest verdict and keeps a skipped one dated\") callback.noRuns","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":461,"symbol":"test(\"mayTouch: a run's files, or a name token in the edited file, make an invariant relevant to an edit\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":834,"symbol":"test(\"a totality oracle's refutation is a recorded event: the refuted line never satisfies it, a record with a later passing run does, and a bullet with bo...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":835,"symbol":"test(\"a totality oracle's refutation is a recorded event: the refuted line never satisfies it, a record with a later passing run does, and a bullet with bo...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":836,"symbol":"test(\"a totality oracle's refutation is a recorded event: the refuted line never satisfies it, a record with a later passing run does, and a bullet with bo...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":837,"symbol":"test(\"a totality oracle's refutation is a recorded event: the refuted line never satisfies it, a record with a later passing run does, and a bullet with bo...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":842,"symbol":"test(\"a totality oracle's refutation is a recorded event: the refuted line never satisfies it, a record with a later passing run does, and a bullet with bo...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":843,"symbol":"test(\"a totality oracle's refutation is a recorded event: the refuted line never satisfies it, a record with a later passing run does, and a bullet with bo...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":844,"symbol":"test(\"a totality oracle's refutation is a recorded event: the refuted line never satisfies it, a record with a later passing run does, and a bullet with bo...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":846,"symbol":"test(\"a totality oracle's refutation is a recorded event: the refuted line never satisfies it, a record with a later passing run does, and a bullet with bo...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":847,"symbol":"test(\"a totality oracle's refutation is a recorded event: the refuted line never satisfies it, a record with a later passing run does, and a bullet with bo...) callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":868,"symbol":"test(\"a structural defect is an invariant whose satisfaction has been removed; a requirement with a failing check stays a requirement\") callback.wasInvariant","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":874,"symbol":"test(\"a structural defect is an invariant whose satisfaction has been removed; a requirement with a failing check stays a requirement\") callback.stillRequirement","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":881,"symbol":"test(\"a structural defect is an invariant whose satisfaction has been removed; a requirement with a failing check stays a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":885,"symbol":"test(\"a structural defect is an invariant whose satisfaction has been removed; a requirement with a failing check stays a requirement\") callback.stale","class":"test","of":"protected","test":true},{"file":"src/enforcement/enforcement.test.ts","line":919,"symbol":"test(\"refute runs the bullet's totality oracle with the break staged, requires it to fail, and appends the refutation record\") callback.before","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":922,"symbol":"test(\"refute runs the bullet's totality oracle with the break staged, requires it to fail, and appends the refutation record\") callback.after","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/run.ts","line":24,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/enforcement/run.ts","line":300,"symbol":"performRun.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/enforcement/run.ts","line":794,"symbol":"gradeRecord.after","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/convergence.ts","line":27,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/convergence.ts","line":253,"symbol":"convergence.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/journal/defects.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/journal/defects.test.ts","line":219,"symbol":"test(\"spec --check names a defect closed with neither a guard nor a decision and a defect in an already guarded class as a guard failure, without counting ...) callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":307,"symbol":"test(\"a family's guard answers only for its own defect, so a later defect in the family is no guard failure, while a class keeps the rule\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":353,"symbol":"test(\"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, ...) callback.window","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":360,"symbol":"test(\"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, ...) callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":443,"symbol":"test(\"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":515,"symbol":"test(\"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/defects.test.ts","line":582,"symbol":"test(\"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end read...) callback.reading","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/journal/verbs.ts","line":52,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/journal/verbs.ts","line":326,"symbol":"checkGuard","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/ci-report.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/ci-report.ts","line":328,"symbol":"buildReport.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/ci.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/ci.test.ts","line":304,"symbol":"test(\"ci report carries each project's problems, chokepoint verdicts, spec gaps and guard failures as Markdown, and fails only when Coherence did not finis...) callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":379,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test() callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":387,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"a project with a recorded run that declares no rules says nothing about rules\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":394,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"no record of a run for the session names the session and says Coherence did not check the rules\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":401,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"a spec gap whose route goes no further than its own component says nothing extra after its source\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":410,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"spec gaps Coherence could not read keep the lead from claiming there is nothing to fix\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":417,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"a project whose changed files were read beside one that was not keeps the lead from claiming none of the findings changed\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":427,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"registry problems are marked when the pull request changed the file they are about\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":445,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"a registry top whose changed files git could not list says so\") callback.project.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":453,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"a path, name or id with backticks or Markdown stays one code span\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":463,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"an unchecked input reaches the stops after its route's first, whatever folder declared it\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/ci.test.ts","line":471,"symbol":"describe(\"ci report says what each finding means and what to do\") callback.test(\"the rules counted in the fold add up across projects\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/delivery.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/delivery.ts","line":53,"symbol":"specFigures.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/hook.ts","line":97,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/hook.ts","line":437,"symbol":"specModelOrNull","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/mirrors.test.ts","line":10,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/mirrors.test.ts","line":119,"symbol":"test(\"a mirror whose list is gone is said at the edit and is a spec problem, never skipped\") callback.problems","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/practice-delivery.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/practice-delivery.ts","line":246,"symbol":"hasSpec","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/project-name.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/project-name.test.ts","line":37,"symbol":"nameProblems","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/project-name.test.ts","line":66,"symbol":"test(\"a stored project name that disagrees with the config's name is a note at the lexicon, never a spec problem; one that agrees, none stored, or no confi...) callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/project-name.test.ts","line":75,"symbol":"test(\"a stored project name that disagrees with the config's name is a note at the lexicon, never a spec problem; one that agrees, none stored, or no confi...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/project-name.test.ts","line":78,"symbol":"test(\"a stored project name that disagrees with the config's name is a note at the lexicon, never a spec problem; one that agrees, none stored, or no confi...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/project-name.test.ts","line":79,"symbol":"test(\"a stored project name that disagrees with the config's name is a note at the lexicon, never a spec problem; one that agrees, none stored, or no confi...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/telemetry.ts","line":31,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/lifecycle/telemetry.ts","line":226,"symbol":"projectFacts","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/lifecycle/upgrade.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/upgrade.test.ts","line":147,"symbol":"test(\"an adopter that enacted every kernel practice as an earlier release taught it re-enacts each and checks clean under this one\") callback.problems","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":27,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/observation/observation.test.ts","line":305,"symbol":"test(\"a runner that attributes coverage only per run is recorded per run, never per test\") callback.record.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":344,"symbol":"test(\"an entrance is exercised when some test executed its handler's body, and never observed otherwise\") callback.record.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/convex.test.ts","line":21,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/convex.test.ts","line":130,"symbol":"test(\"a project that does not name the Convex plugin pays nothing for it: no file of the plugin read, no rule, no well-known name, no vocabulary; one that ...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/languages.test.ts","line":25,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/languages.test.ts","line":205,"symbol":"test(\"a plugin that provides a language no bundled plugin does is read as a bundled one is, for its project alone: its files, tests, folders, entrance rule...) callback.problems","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/languages.test.ts","line":219,"symbol":"test(\"a plugin that provides a language no bundled plugin does is read as a bundled one is, for its project alone: its files, tests, folders, entrance rule...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":24,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/plugins.test.ts","line":121,"symbol":"test(\"a via form is proved by the plugin that declares it, graded like a test with its evidence label; a form no plugin declares is a spec problem naming t...) callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":151,"symbol":"test(\"two plugins that provide one language are refused with both named, and so is a plugin written for another pluginApi\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":169,"symbol":"test(\"a plugin's lexicon layer joins the stack: its terms count as declared and show their layer, its rejected names stay its own, its defect classes are r...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":178,"symbol":"test(\"a project without a plugins key reads nothing of any plugin: no manifest, no lexicon layer, no bundled folder\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/build.ts","line":40,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/readings/scope/build.ts","line":148,"symbol":"loadSpec.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/scope/component-interfaces.test.ts","line":35,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/component-interfaces.test.ts","line":310,"symbol":"test(\"a file the language server cannot answer for is named and left unread while the rest of the language is read\") callback.observed","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/component-interfaces.ts","line":91,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/readings/scope/component-interfaces.ts","line":643,"symbol":"readComponentInterfaces.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/scope/gaps.ts","line":62,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/readings/scope/gaps.ts","line":165,"symbol":"specShape","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/readings/scope/languages-read.test.ts","line":32,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/languages-read.test.ts","line":79,"symbol":"test(\"no reading takes the primary language alone without naming the languages it left unread, and every renderer prints them\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/live.test.ts","line":17,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/live.test.ts","line":301,"symbol":"test(\"every file the spec model reads by name refreshes the live reading: each spec and practice file it read for a project with components and a practice,...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/multi-language.test.ts","line":23,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/multi-language.test.ts","line":96,"symbol":"test(\"entrance detection in a two-language project finds each language's entrances by its own rules\") callback.measured","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/multi-language.test.ts","line":164,"symbol":"test(\"an observation of a multi-language project names the languages it did not read\") callback.record.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/multi-language.test.ts","line":196,"symbol":"test(\"a single-language project reads as it always did: one language read, no languages line printed\") callback.measured","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/structure-flow.test.ts","line":24,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/structure-flow.test.ts","line":785,"symbol":"test(\"an entrance is declared in its component's spec and checked: an unresolvable handler is a spec problem, and one no interface reaches is unreachable\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/structure-flow.test.ts","line":1991,"symbol":"test(\"the reading traces the chokepoints a handler passes: a wrapper around it, one further along its reach, a declared guard at its registration, and a mo...) callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/undeclared.ts","line":24,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/readings/scope/undeclared.ts","line":56,"symbol":"undeclaredNow.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":54,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/scaffold/cli.ts","line":217,"symbol":"askedOf.components","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/cli.ts","line":336,"symbol":"entrancesVerb.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/scaffold/entrances.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/scaffold/entrances.test.ts","line":66,"symbol":"test(\"scaffold entrances proposes a bullet in the spec grammar for every undeclared entrance, under the spec of the component owning its file, that covers ...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/entrances.test.ts","line":134,"symbol":"test(\"scaffold entrances on a Next.js app shaped like ai-chatbot proposes the request proxy, the GET and POST its NextAuth route re-exports, and its page r...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/import.test.ts","line":12,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/scaffold/import.test.ts","line":170,"symbol":"test(\"scaffold import tach --write creates only the specs that do not exist, reports each one skipped, and what it writes parses\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/scaffold/scaffold.test.ts","line":71,"symbol":"test(\"scaffold component creates the folder and a spec with the intent and an empty invariants section, and refuses to overwrite\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":131,"symbol":"test(\"scaffold invariant --write appends to the invariants section, and the result parses as a requirement with unfilled slots\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":169,"symbol":"test(\"an unfilled slot is one of the forms the scaffold prints, not any prose in angle brackets\") callback.scaffolded","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/scaffold/scaffold.test.ts","line":197,"symbol":"test(\"an unfilled slot is one of the forms the scaffold prints, not any prose in angle brackets\") callback.real","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/cli.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"src/spec/cli.ts","line":47,"symbol":"specCommand.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/spec/cli.ts","line":81,"symbol":"registryCheck.model","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/spec/covers.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/covers.test.ts","line":25,"symbol":"withModel","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/dead-triggers.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/dead-triggers.test.ts","line":44,"symbol":"dead","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/floor.test.ts","line":13,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/floor.test.ts","line":67,"symbol":"messages","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/floor.test.ts","line":73,"symbol":"test(\"an invariant the run store graded is not demoted, removed, or renamed away without a decision naming it; a requirement never graded is free\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/model.ts","line":25,"symbol":"module top level","class":"inside","of":"protected","test":false,"form":"import"},{"file":"src/spec/model.ts","line":538,"symbol":"loadSpecModel","class":"inside","of":"protected","test":false},{"file":"src/spec/model.ts","line":917,"symbol":"projectPractices","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/spec/practice.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/practice.test.ts","line":191,"symbol":"test(\"a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text\") callback.messages","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":198,"symbol":"test(\"a practice file stands only beside its folder's spec, with the spec's stem\") callback.messages","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":202,"symbol":"test(\"a practice file stands only beside its folder's spec, with the spec's stem\") callback.model","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":210,"symbol":"test(\"every record a practice cites must exist, and every invariant it names must be declared\") callback.messages","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":238,"symbol":"describe(\"a cited commit is no commit only where git can tell\") callback.test(`a ${clone} clone citing ${cited}: ${problem ? \"a problem\" : \"no problem\"}`) callback.messages","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":260,"symbol":"test(\"an enactment needs an outcome for every step, a because for a deviation or a skip, and keeps the text it enacted\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":262,"symbol":"test(\"an enactment needs an outcome for every step, a because for a deviation or a skip, and keeps the text it enacted\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":269,"symbol":"test(\"a step enacted and since removed is a problem until a decision cites an enactment of the practice\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":274,"symbol":"test(\"a step enacted and since removed is a problem until a decision cites an enactment of the practice\") callback.messages","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":279,"symbol":"test(\"a step enacted and since removed is a problem until a decision cites an enactment of the practice\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":285,"symbol":"test(\"a step enacted and since removed is a problem until a decision cites an enactment of the practice\") callback.again","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":290,"symbol":"test(\"a step enacted and since removed is a problem until a decision cites an enactment of the practice\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":292,"symbol":"test(\"a step enacted and since removed is a problem until a decision cites an enactment of the practice\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":392,"symbol":"test(\"scaffold practice prints every slot, refuses a folder without a spec, and writes the practice file beside the spec\") callback.messages","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":404,"symbol":"test(\"in Coherence's own tree every practice declares its reach, kernel or internal; anywhere else a reach line is a problem\") callback.unsaid","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":409,"symbol":"test(\"in Coherence's own tree every practice declares its reach, kernel or internal; anywhere else a reach line is a problem\") callback.messages","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":413,"symbol":"test(\"in Coherence's own tree every practice declares its reach, kernel or internal; anywhere else a reach line is a problem\") callback.adopter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/practice.test.ts","line":446,"symbol":"test(\"in an adopter, a kernel practice a Coherence release changed asks no amendment: enact goes through and spec --check names no floor gap\") callback.floor","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/spec.test.ts","line":15,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/spec/spec.test.ts","line":18,"symbol":"module top level","class":"test","of":"protected","test":true,"form":"import"},{"file":"src/spec/spec.test.ts","line":55,"symbol":"withModel","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/spec/spec.test.ts","line":146,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":155,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":156,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":166,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":167,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":169,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":170,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":173,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":174,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":177,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":178,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":181,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":182,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":185,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback.derived","class":"test","of":"protected","test":true},{"file":"src/spec/spec.test.ts","line":191,"symbol":"test(\"the state derivation: the full bullet is an invariant, and each missing part keeps it a requirement\") callback","class":"test","of":"protected","test":true}],"testReferences":35,"files":["src/adapters/ignore-files.test.ts","src/economy/closure.ts","src/economy/mass.ts","src/enforcement/cli.ts","src/enforcement/enforcement.test.ts","src/enforcement/run.ts","src/journal/convergence.ts","src/journal/defects.test.ts","src/journal/verbs.ts","src/lifecycle/ci-report.ts","src/lifecycle/ci.test.ts","src/lifecycle/delivery.ts","src/lifecycle/hook.ts","src/lifecycle/mirrors.test.ts","src/lifecycle/practice-delivery.ts","src/lifecycle/project-name.test.ts","src/lifecycle/telemetry.ts","src/lifecycle/upgrade.test.ts","src/observation/observation.test.ts","src/plugins/convex.test.ts","src/plugins/languages.test.ts","src/plugins/plugins.test.ts","src/readings/scope/build.ts","src/readings/scope/component-interfaces.test.ts","src/readings/scope/component-interfaces.ts","src/readings/scope/gaps.ts","src/readings/scope/languages-read.test.ts","src/readings/scope/live.test.ts","src/readings/scope/multi-language.test.ts","src/readings/scope/structure-flow.test.ts","src/readings/scope/undeclared.ts","src/scaffold/cli.ts","src/scaffold/entrances.test.ts","src/scaffold/import.test.ts","src/scaffold/scaffold.test.ts","src/spec/cli.ts","src/spec/covers.test.ts","src/spec/dead-triggers.test.ts","src/spec/floor.test.ts","src/spec/model.ts","src/spec/practice.test.ts","src/spec/spec.test.ts","src/spec/state.ts"],"latency":299,"reason":"deriveState is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/spec/state.ts:68 reads \"export function deriveState(invariant: Invariant, applicable\"); every reference in the project is inside the chokepoint; 35 test references","state":"invariant","enforces":["loadSpecModel"]}]} +{"at":"2026-10-27T22:16:06.826Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e336378","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":16142,"load":{"average":5.52,"cores":14},"invariants":[{"component":"src/adapters","name":"name forms","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sitesRef":{"hash":"sha256:a57855d4f012cbdd0dcfb4f17f582f7369f9bebb1533140c141ba472d32a81b3","at":"2026-10-27T22:15:41.516Z"},"testReferences":0,"files":["plugins/convex/convex.ts","plugins/declared/declared.ts","plugins/go/go.ts","plugins/python/python.ts","plugins/rust/rust.ts","plugins/typescript/typescript.ts","src/adapters/adapter.test.ts","src/adapters/adapter.ts","src/economy/mass.ts","src/enforcement/run.ts","src/plugins/api.ts"],"latency":2050,"reason":"IDENTIFIER in adapter.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/adapters/adapter.ts:277 declares IDENTIFIER without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["parseName"]},{"component":"src/adapters","name":"ladder is adapter-defined","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:47b03658b161b13cb81a06e7dc09513fe0b372c43cc73be75fc25ba35e3fc82c","at":"2026-10-27T22:15:41.516Z"},"testReferences":4,"files":["plugins/typescript/index.ts","plugins/typescript/typescript.ts","src/adapters/adapter.test.ts","src/adapters/listing.test.ts","src/adapters/project-files.test.ts","src/economy/economy.test.ts","src/enforcement/enforcement.test.ts","src/enforcement/from.test.ts","src/enforcement/javascript.test.ts","src/enforcement/server.test.ts","src/lifecycle/hook-speed.test.ts","src/lifecycle/monorepo.test.ts","src/lifecycle/work-meter.test.ts","src/observation/observation.test.ts","src/readings/scope/component-interfaces.test.ts"],"latency":330,"reason":"TYPESCRIPT_LADDER is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (plugins/typescript/typescript.ts:94 reads \"export const TYPESCRIPT_LADDER: Ladder = manifest.ladder as \"); every reference in the project is inside the chokepoint; 4 test references","state":"invariant","enforces":["TypeScriptAdapter"]},{"component":"src/adapters","name":"Python rungs verified","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:1b0aaa1667d10e41d1c512354beef50fdd26b7c708e7dae6fa4741a5907060e3","at":"2026-10-27T22:15:41.516Z"},"testReferences":8,"files":["plugins/python/index.ts","plugins/python/python.ts","src/adapters/adapter.test.ts","src/adapters/listing.test.ts","src/adapters/python-from.test.ts","src/adapters/python.test.ts","src/adapters/tach.test.ts","src/lifecycle/monorepo.test.ts","src/observation/observation.test.ts","src/readings/scope/component-interfaces.test.ts"],"latency":270,"reason":"PYTHON_LADDER is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (plugins/python/python.ts:129 reads \"export const PYTHON_LADDER: Ladder = manifest.ladder as Ladd\"); every reference in the project is inside the chokepoint; 8 test references","state":"invariant","enforces":["PythonAdapter"]},{"component":"src/adapters","name":"Rust rungs verified","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:d39e7a430ce10856efd12ca9e8073055bd88450ee49aa920d8bf9021bad8c197","at":"2026-10-27T22:15:41.516Z"},"testReferences":9,"files":["plugins/rust/index.ts","plugins/rust/rust.ts","src/adapters/adapter.test.ts","src/adapters/rust.test.ts"],"latency":249,"reason":"RUST_LADDER is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (plugins/rust/rust.ts:89 reads \"export const RUST_LADDER: Ladder = manifest.ladder as Ladder\"); every reference in the project is inside the chokepoint; 9 test references","state":"invariant","enforces":["RustAdapter"]},{"component":"src/adapters","name":"rust-analyzer located or a reason","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sitesRef":{"hash":"sha256:e8a2a9b0d0b9a3336c15b5431ef47626f6d11ca6df20a2839b74b6d82f6140da","at":"2026-10-27T22:15:41.516Z"},"testReferences":0,"files":["plugins/rust/index.ts","plugins/rust/rust.ts","src/adapters/adapter.test.ts","src/adapters/rust.test.ts"],"latency":1084,"reason":"SERVER_BIN in rust.ts is visibility-choked, enforced by the compiler: not visible outside its module (plugins/rust/rust.ts:73 declares SERVER_BIN without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["plugins/rust/rust.ts"]},{"component":"src/adapters","name":"pytest report mapped by name","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:db56024139f07d1cc988055f9ebc6cffb8c3133f16fad766fb69f8411ce2e241","at":"2026-10-27T22:15:41.516Z"},"testReferences":2,"files":["src/adapters/python.test.ts","src/enforcement/latency.test.ts","src/enforcement/totality.ts"],"latency":228,"reason":"reportFromJunit is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/totality.ts:151 reads \"export function reportFromJunit(xml: string): JsonReport {\"); every reference in the project is inside the chokepoint; 2 test references","state":"invariant","enforces":["parseReport"]},{"component":"src/adapters","name":"server located or a reason","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"plugins/typescript/index.ts","line":8,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/typescript/index.ts","line":11,"symbol":"typescript.adapter","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript-source.ts","line":11,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":false,"form":"import"},{"file":"plugins/typescript/typescript-source.ts","line":32,"symbol":"TYPESCRIPT_RESOLVE.modulePaths","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":98,"symbol":"locateServer","class":"inside","of":"protected","test":false},{"file":"plugins/typescript/typescript.ts","line":98,"symbol":"locateServer","class":"inside","of":"protected","test":false},{"file":"plugins/typescript/typescript.ts","line":157,"symbol":"seedFile.sources","class":"inside","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":163,"symbol":"firstSourceFile.found","class":"inside","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":246,"symbol":"resolveSpecifier.candidates","class":"inside","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":262,"symbol":"TypeScriptAdapter.ladder","class":"inside","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":300,"symbol":"TypeScriptAdapter.start.server","class":"inside","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":302,"symbol":"TypeScriptAdapter.start.reason","class":"inside","of":"protected","test":false},{"file":"plugins/typescript/typescript.ts","line":341,"symbol":"TypeScriptAdapter.start.reason","class":"inside","of":"protected","test":false},{"file":"plugins/typescript/typescript.ts","line":545,"symbol":"TypeScriptAdapter.searchWorkspace","class":"inside","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":615,"symbol":"TypeScriptAdapter.references.form","class":"inside","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":663,"symbol":"TypeScriptAdapter.wildcardReExports","class":"inside","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":673,"symbol":"TypeScriptAdapter.wildcardReExports.target","class":"inside","of":"chokepoint","test":false},{"file":"plugins/typescript/typescript.ts","line":804,"symbol":"TypeScriptAdapter.awaitRefusal.refusal.find() callback","class":"inside","of":"chokepoint","test":false},{"file":"src/adapters/adapter.test.ts","line":11,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/adapter.test.ts","line":56,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":63,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/adapter.test.ts","line":68,"symbol":"test(\"the grade ladder's top rung is adapter-defined: TypeScript and Rust enforce visibility, Python does not\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/declared-server.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/declared-server.test.ts","line":29,"symbol":"located","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/listing.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/listing.test.ts","line":53,"symbol":"test(\"the TypeScript adapter reads the project's files once per forget: a file created after the listing is found only after a forget\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/listing.test.ts","line":88,"symbol":"test(\"a cold server resolves a name the project declares even when the first source file of the walk lies outside the TypeScript project\") callback.seedFile","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/listing.test.ts","line":96,"symbol":"test(\"a cold server resolves a name the project declares even when the first source file of the walk lies outside the TypeScript project\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/listing.test.ts","line":116,"symbol":"test(\"the TypeScript adapter spawns git a fixed number of times between forgets, whatever the number of names asked\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/project-files.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/project-files.test.ts","line":72,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/project-files.test.ts","line":94,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/project-files.test.ts","line":160,"symbol":"test(\"a folder the config names as a plugin is not the project's source: its files are walked by nothing and graded by nothing, its declarations shadow not...) callback.own","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/project-files.test.ts","line":180,"symbol":"test(\"a folder the config names as a plugin is not the project's source: its files are walked by nothing and graded by nothing, its declarations shadow not...) callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":10,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/specifiers.test.ts","line":10,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/specifiers.test.ts","line":10,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/specifiers.test.ts","line":10,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/adapters/specifiers.test.ts","line":13,"symbol":"test(\"a NodeNext specifier written with .js names the TypeScript source first, and the JavaScript file only where that is what exists\") callback.candidates","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":16,"symbol":"test(\"a NodeNext specifier written with .js names the TypeScript source first, and the JavaScript file only where that is what exists\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":18,"symbol":"test(\"a NodeNext specifier written with .js names the TypeScript source first, and the JavaScript file only where that is what exists\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":19,"symbol":"test(\"a NodeNext specifier written with .js names the TypeScript source first, and the JavaScript file only where that is what exists\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":23,"symbol":"test(\"an extensionless specifier has JavaScript and folder-index candidates, in TypeScript-first order\") callback.candidates","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":28,"symbol":"test(\"an extensionless specifier has JavaScript and folder-index candidates, in TypeScript-first order\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":29,"symbol":"test(\"an extensionless specifier has JavaScript and folder-index candidates, in TypeScript-first order\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":30,"symbol":"test(\"an extensionless specifier has JavaScript and folder-index candidates, in TypeScript-first order\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":31,"symbol":"test(\"an extensionless specifier has JavaScript and folder-index candidates, in TypeScript-first order\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":36,"symbol":"test(\"compiled JavaScript a repository tracks beside its TypeScript is not a source: the seed and the text search stay on the TypeScript\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":37,"symbol":"test(\"compiled JavaScript a repository tracks beside its TypeScript is not a source: the seed and the text search stay on the TypeScript\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":38,"symbol":"test(\"compiled JavaScript a repository tracks beside its TypeScript is not a source: the seed and the text search stay on the TypeScript\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/adapters/specifiers.test.ts","line":39,"symbol":"test(\"compiled JavaScript a repository tracks beside its TypeScript is not a source: the seed and the text search stay on the TypeScript\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/economy/economy.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/economy/economy.test.ts","line":14,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/economy/economy.test.ts","line":77,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/economy/economy.test.ts","line":78,"symbol":"serverPresent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/economy/economy.test.ts","line":95,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/enforcement.test.ts","line":120,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":122,"symbol":"serverPresent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":139,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":508,"symbol":"test(\"the check reads the current disk text after a forget, with the instrument's watcher blind to the file: a loop of edit-then-check yields zero wrong ve...) callback.fresh","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":538,"symbol":"test(\"every site the language server reports is a reference: a bypass beneath a semicolon-less bare import is a bypass, and an import outside the chokepoin...) callback.fresh","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":566,"symbol":"ruledTree","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":578,"symbol":"ruledTree.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/enforcement.test.ts","line":790,"symbol":"test(\"the automatic refutation is vacuous unless the check's own classification calls the synthetic site a bypass\") callback.fresh","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":18,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/from.test.ts","line":64,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/from.test.ts","line":82,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/javascript.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/javascript.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/javascript.test.ts","line":64,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/javascript.test.ts","line":66,"symbol":"serverPresent","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/javascript.test.ts","line":80,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/javascript.test.ts","line":152,"symbol":"test(\"a TypeScript project that tracks its compiled output: the seed, the resolution and the cold-start text search stay on the TypeScript source\") callback.fresh","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/enforcement/server.test.ts","line":19,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/enforcement/server.test.ts","line":84,"symbol":"test(\"a served refutation stages what the adapter in process stages, the exempt folder and the occasion carried\") callback.local","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":16,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/hook-speed.test.ts","line":138,"symbol":"test(\"an edit says which chokepoint invariants it could not check, and stays silent only for a value the spec writes as prose\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/hook-speed.test.ts","line":158,"symbol":"test(\"a protected name in a file of none of the project's languages starts no check at the edit; the same name in its code does\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":20,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/monorepo.test.ts","line":242,"symbol":"test(\"a chokepoint verdict over a nested project says its reference search covered that folder alone\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/monorepo.test.ts","line":292,"symbol":"underHorizon.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/lifecycle/work-meter.test.ts","line":41,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/lifecycle/work-meter.test.ts","line":598,"symbol":"test(\"an edit's chokepoint check never goes silent because a cache cannot be used\") callback.adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":21,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/observation/observation.test.ts","line":100,"symbol":"adapter","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/observation/observation.test.ts","line":137,"symbol":"before() callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/plugins/plugins.test.ts","line":16,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/plugins/plugins.test.ts","line":97,"symbol":"test(\"a plugin that extends a language answers its chokepoint checks: the adapter is the plugin's, wrapping the core's, and the run entry names the plugin\") callback","class":"chokepoint-reference","of":"chokepoint","test":true},{"file":"src/readings/scope/component-interfaces.test.ts","line":26,"symbol":"module top level","class":"chokepoint-reference","of":"chokepoint","test":true,"form":"import"},{"file":"src/readings/scope/component-interfaces.test.ts","line":218,"symbol":"test(\"the prefilter never hides a cross-component reference\") callback.tsReadings","class":"chokepoint-reference","of":"chokepoint","test":true}],"testReferences":0,"files":["plugins/typescript/index.ts","plugins/typescript/typescript-source.ts","plugins/typescript/typescript.ts","src/adapters/adapter.test.ts","src/adapters/declared-server.test.ts","src/adapters/listing.test.ts","src/adapters/project-files.test.ts","src/adapters/specifiers.test.ts","src/economy/economy.test.ts","src/enforcement/enforcement.test.ts","src/enforcement/from.test.ts","src/enforcement/javascript.test.ts","src/enforcement/server.test.ts","src/lifecycle/hook-speed.test.ts","src/lifecycle/monorepo.test.ts","src/lifecycle/work-meter.test.ts","src/observation/observation.test.ts","src/plugins/plugins.test.ts","src/readings/scope/component-interfaces.test.ts"],"latency":1019,"reason":"SERVER_BIN in plugins/typescript/typescript.ts is visibility-choked, enforced by the compiler: not visible outside its module (plugins/typescript/typescript.ts:57 declares SERVER_BIN without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["plugins/typescript/typescript.ts"]},{"component":"src/economy","name":"calibrate label never manual","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:ef0a1016e54e9c72483db57451e1e2faa9cbf508e4d6323d8a4c39626e26533b","at":"2026-10-27T22:15:41.516Z"},"testReferences":3,"files":["src/economy/calibrate.ts","src/economy/economy.test.ts"],"latency":281,"reason":"labelSnapshot is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/economy/calibrate.ts:76 reads \"export function labelSnapshot(root: string, snapshot: Snapsh\"); every reference in the project is inside the chokepoint; 3 test references","state":"invariant","enforces":["sampleOf"]},{"component":"src/enforcement","name":"run appended never rewritten","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:50affd4c9598f7bd152dac93a632a1368af474f1a851a04e01acd622c708fc87","at":"2026-10-27T22:15:41.516Z"},"testReferences":43,"files":["src/adapters/declared.test.ts","src/adapters/python.test.ts","src/economy/economy.test.ts","src/enforcement/cli.ts","src/enforcement/enforcement.test.ts","src/enforcement/from.test.ts","src/enforcement/languages.test.ts","src/enforcement/record.ts","src/enforcement/run-sites.test.ts","src/enforcement/run.ts","src/enforcement/server.test.ts","src/journal/shards.test.ts","src/lifecycle/ci.test.ts","src/lifecycle/hook.ts","src/lifecycle/work-meter.test.ts","src/observation/observation.test.ts","src/plugins/check.ts","src/plugins/convex.test.ts","src/plugins/plugins.test.ts","src/plugins/quint.test.ts","src/spec/floor.test.ts"],"latency":346,"reason":"appendRun is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/record.ts:332 reads \"export function appendRun(root: string, record: RunRecord): \"); every reference in the project is inside the chokepoint; 43 test references","state":"invariant","enforces":["performRun"]},{"component":"src/enforcement","name":"automatic refutation","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:e3a511d346f77577696cf4df0310ba83d4171f7b2b23583418220a6f2aebda80","at":"2026-10-27T22:15:41.516Z"},"testReferences":71,"files":["src/adapters/declared-server.test.ts","src/adapters/declared.test.ts","src/adapters/project-files.test.ts","src/adapters/python-from.test.ts","src/adapters/python.test.ts","src/adapters/rust.test.ts","src/adapters/tach.test.ts","src/enforcement/check.ts","src/enforcement/cli.ts","src/enforcement/enforcement.test.ts","src/enforcement/from.test.ts","src/enforcement/javascript.test.ts","src/enforcement/languages.test.ts","src/enforcement/run.ts","src/enforcement/server.test.ts","src/lifecycle/hook.ts","src/lifecycle/monorepo.test.ts","src/observation/observation.test.ts","src/plugins/check.ts","src/plugins/convex.test.ts","src/plugins/plugins.test.ts","src/plugins/quint.test.ts"],"latency":329,"reason":"checkChokepoint is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/check.ts:204 reads \"export async function checkChokepoint(adapter: LanguageAdapt\"); every reference in the project is inside the chokepoint; 71 test references","state":"invariant","enforces":["performRun"]},{"component":"src/enforcement","name":"one invocation for every test","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:e0ac3142c2152b3c3e8561039f01cbf5ec01c3d01bfb811a4b51bfab5f0ccca4","at":"2026-10-27T22:15:41.516Z"},"testReferences":1,"files":["src/adapters/declared.test.ts","src/adapters/python.test.ts","src/enforcement/cli.ts","src/enforcement/enforcement.test.ts","src/enforcement/from.test.ts","src/enforcement/languages.test.ts","src/enforcement/run.ts","src/enforcement/server.test.ts","src/enforcement/totality.ts","src/lifecycle/hook.ts","src/observation/observation.test.ts","src/plugins/check.ts","src/plugins/convex.test.ts","src/plugins/plugins.test.ts","src/plugins/quint.test.ts"],"latency":224,"reason":"runTotalityBatch is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/totality.ts:268 reads \"export async function runTotalityBatch(root: string, config:\"); every reference in the project is inside the chokepoint; 1 test reference","state":"invariant","enforces":["performRun"]},{"component":"src/enforcement","name":"warm server the only path","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:09f188702a4555bf74e7e011025165730fda322e88bbc4b5d3c5ea5b4b206af1","at":"2026-10-27T22:15:41.516Z"},"testReferences":15,"files":["src/economy/cli.ts","src/enforcement/run.ts","src/enforcement/server.test.ts","src/enforcement/server.ts","src/readings/scope/live.test.ts"],"latency":267,"reason":"connectAdapter is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/enforcement/server.ts:917 reads \"export async function connectAdapter(rootGiven: string, opti\"); every reference in the project is inside the chokepoint; 15 test references","state":"invariant","enforces":["withWarmAdapters"]},{"component":"src/journal","name":"a record is vetted before it is written","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:3a6500a6af98945d6ae7e24567f87cee09201331fc44cb7b28f90bff3eec2659","at":"2026-10-27T22:15:41.516Z"},"testReferences":2,"files":["src/journal/shards.test.ts","src/journal/work.ts","src/journal/workVerbs.ts"],"latency":250,"reason":"appendWork is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/work.ts:43 reads \"export function appendWork(cwd: string, record: WorkRecord):\"); every reference in the project is inside the chokepoint; 2 test references","state":"invariant","enforces":["writeWork"]},{"component":"src/journal","name":"append-only store","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:b79fd5a4f784482ed36fe19378e647c36a4942a394794244e06c97a2342af2e6","at":"2026-10-27T22:15:41.516Z"},"testReferences":0,"files":["src/cli.ts","src/economy/calibrate.ts","src/economy/economy.test.ts","src/enforcement/cli.ts","src/enforcement/run.ts","src/enforcement/test-budgets.test.ts","src/enforcement/test-budgets.ts","src/journal/branches.ts","src/journal/cli.ts","src/journal/convergence.ts","src/journal/dead-ends.ts","src/journal/defects.test.ts","src/journal/feed.ts","src/journal/journal.test.ts","src/journal/read.ts","src/journal/shards.test.ts","src/journal/store.ts","src/journal/verbs.ts","src/journal/workVerbs.ts","src/lifecycle/delivery.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/lexicon-baseline.ts","src/lifecycle/lexicon-coverage.ts","src/lifecycle/lexicon-maintain.ts","src/lifecycle/lexicon-work.test.ts","src/lifecycle/practice-delivery.ts","src/lifecycle/state-files.test.ts","src/lifecycle/statusline.test.ts","src/lifecycle/vocabulary-state.ts","src/lifecycle/work-meter.test.ts","src/observation/observed.ts","src/readings/query/cli.ts","src/readings/scope/build.ts","src/readings/scope/gaps.ts","src/readings/scope/live.test.ts","src/readings/scope/live.ts","src/spec/practice.test.ts","src/spec/practices.ts"],"latency":437,"reason":"journalDir is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/store.ts:25 reads \"export function journalDir(cwd: string): string {\"); every reference in the project is inside the chokepoint","state":"invariant","enforces":["src/journal/store.ts"]},{"component":"src/journal","name":"attributed writes","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:96ab844c0733edf5a4826a4af1d59b50d3088cf26eb6e61b2a24926cb4074c36","at":"2026-10-27T22:15:41.516Z"},"testReferences":22,"files":["src/economy/economy.test.ts","src/journal/shards.test.ts","src/journal/store.ts","src/journal/verbs.ts","src/lifecycle/work-meter.test.ts","src/spec/practice.test.ts"],"latency":126,"reason":"appendRecord is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/store.ts:45 reads \"export function appendRecord(cwd: string, record: JournalRec\"); every reference in the project is inside the chokepoint; 22 test references","state":"invariant","enforces":["write in verbs.ts"]},{"component":"src/journal","name":"one id minter","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:4677c4a92ab77b9bd566b223e95e64080a7db021af7193b27a66565a7274ad5b","at":"2026-10-27T22:15:41.516Z"},"testReferences":5,"files":["src/journal/record.ts","src/journal/verbs.ts","src/journal/vocabularies.test.ts","src/journal/workVerbs.ts","src/readings/scope/practices.test.ts"],"latency":252,"reason":"recordId is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/record.ts:287 reads \"export function recordId(kind: Kind | WorkKind, session: str\"); every reference in the project is inside the chokepoint; 5 test references","state":"invariant","enforces":["head in verbs.ts"]},{"component":"src/lifecycle","name":"regulate refuses only what it can prove","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:4730103abdf8603091c1842ba0d51bbb20ec0b977f174ca951b20681b59c61d7","at":"2026-10-27T22:15:41.516Z"},"testReferences":9,"files":["src/cli.ts","src/enforcement/enforcement.test.ts","src/lifecycle/hook-serve.ts","src/lifecycle/hook-speed.test.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/install.test.ts","src/lifecycle/lexicon-work.test.ts","src/lifecycle/mirrors.test.ts","src/lifecycle/monorepo.test.ts","src/lifecycle/registry.test.ts","src/lifecycle/stop-delivery.test.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/version.test.ts","src/lifecycle/vocabulary-signal.test.ts","src/lifecycle/work-meter.test.ts","src/spec/practice.test.ts"],"latency":319,"reason":"REFUSE_EXIT is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/hook.ts:123 reads \"export const REFUSE_EXIT = 2;\"); every reference in the project is inside the chokepoint; 9 test references","state":"invariant","enforces":["runHook"]},{"component":"src/lifecycle","name":"the hook answers one project","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:7932b8b9121c2011e7ef20e983ca50178733bd3fbc88833f49c8e92f2309e3b0","at":"2026-10-27T22:15:41.516Z"},"testReferences":3,"files":["src/cli.ts","src/enforcement/enforcement.test.ts","src/lifecycle/hook-serve.ts","src/lifecycle/hook-speed.test.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/lexicon-work.test.ts","src/lifecycle/mirrors.test.ts","src/lifecycle/monorepo.test.ts","src/lifecycle/registry.test.ts","src/lifecycle/stop-delivery.test.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/version.test.ts","src/lifecycle/vocabulary-signal.test.ts","src/lifecycle/work-meter.test.ts","src/spec/practice.test.ts"],"latency":241,"reason":"OUTSIDE_ROOT_EXIT is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/hook.ts:131 reads \"export const OUTSIDE_ROOT_EXIT = 78;\"); every reference in the project is inside the chokepoint; 3 test references","state":"invariant","enforces":["runHook"]},{"component":"src/lifecycle","name":"install keeps other hooks","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:69d5b59f1fa4c898445b5f9ae17bd443588dbdf549ebffcbe396fa3f66a751a2","at":"2026-10-27T22:15:41.516Z"},"testReferences":7,"files":["src/cli.ts","src/lifecycle/install.test.ts","src/lifecycle/install.ts"],"latency":252,"reason":"mergeHooks is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/install.ts:275 reads \"export function mergeHooks(settings: Record\"); every reference in the project is inside the chokepoint; 7 test references","state":"invariant","enforces":["install"]},{"component":"src/lifecycle","name":"the update check adds no wait to a hook","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:959d220df98914c1fd51ddf0a858ab5ceb904244100a66407b2aee5857bae41e","at":"2026-10-27T22:15:41.516Z"},"testReferences":3,"files":["src/cli.ts","src/lifecycle/version.test.ts","src/lifecycle/version.ts"],"latency":235,"reason":"refreshLatest is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/version.ts:338 reads \"export async function refreshLatest(env: Env = process.env, \"); every reference in the project is inside the chokepoint; 3 test references","state":"invariant","enforces":["versionCommand"]},{"component":"src/lifecycle","name":"cursor advances after the print","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:b9dd2b3bc567f0ec9de4a8d7ea7e46a444e001c79a0e71877510a2911ba2c836","at":"2026-10-27T22:15:41.516Z"},"testReferences":2,"files":["src/journal/feed.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/work-meter.test.ts"],"latency":205,"reason":"writeCursor is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/journal/feed.ts:71 reads \"export function writeCursor(root: string, session: string, c\"); every reference in the project is inside the chokepoint; 2 test references","state":"invariant","enforces":["src/journal/feed.ts"]},{"component":"src/lifecycle","name":"a hook voice file stays inside the root","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:c7b3bf8c90c054f3c512163a6ad00e15c9fbc101823e1b52dab9f2070c651188","at":"2026-10-27T22:15:41.516Z"},"testReferences":0,"files":["src/lifecycle/hook.ts"],"latency":167,"reason":"HOOK_VOICE_DIR is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/hook.ts:1140 reads \"export const HOOK_VOICE_DIR = join(\".coherence\", \"hooks\");\"); every reference in the project is inside the chokepoint","state":"invariant","enforces":["voiceFile"]},{"component":"src/lifecycle","name":"the corpus is read only through readCorpus","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:a931e6053f5267cd6cfcf21ee7bc36ecb2d038d3940ea4eadd348c59a326e6d8","at":"2026-10-27T22:15:41.516Z"},"testReferences":6,"files":["src/adapters/ignore-files.test.ts","src/adapters/project-files.test.ts","src/adapters/walks.test.ts","src/lifecycle/check.ts","src/lifecycle/lexicon-coverage.ts"],"latency":257,"reason":"collectFiles is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/check.ts:290 reads \"export async function collectFiles(options: CheckOptions): P\"); every reference in the project is inside the chokepoint; 6 test references","state":"invariant","enforces":["readCorpus"]},{"component":"src/lifecycle","name":"only runHook opens a work scope","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:19a0638b2f18de2b1ab07a7d45b40097a24610f630847b9cbe900aad58cd711f","at":"2026-10-27T22:15:41.516Z"},"testReferences":12,"files":["src/cli.ts","src/enforcement/enforcement.test.ts","src/lifecycle/hook-serve.ts","src/lifecycle/hook-speed.test.ts","src/lifecycle/hook.test.ts","src/lifecycle/hook.ts","src/lifecycle/lexicon-work.test.ts","src/lifecycle/mirrors.test.ts","src/lifecycle/monorepo.test.ts","src/lifecycle/registry.test.ts","src/lifecycle/stop-delivery.test.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/version.test.ts","src/lifecycle/vocabulary-signal.test.ts","src/lifecycle/work-meter.test.ts","src/lifecycle/work-meter.ts","src/readings/scope/live.test.ts","src/spec/dead-triggers.test.ts","src/spec/practice.test.ts"],"latency":300,"reason":"openWork is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/work-meter.ts:76 reads \"export function openWork(): WorkScope {\"); every reference in the project is inside the chokepoint; 12 test references","state":"invariant","enforces":["runHook"]},{"component":"src/lifecycle","name":"telemetry is sent only on opt-in","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:2a431bc6373eb25105efa3067f5a28f17570ed821f9117703f21988a5001e3d7","at":"2026-10-27T22:15:41.516Z"},"testReferences":0,"files":["src/lifecycle/telemetry-cli.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/telemetry.ts"],"latency":245,"reason":"FETCH_SENDER is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/telemetry.ts:544 reads \"export const FETCH_SENDER: Sender = async (url, body, timeou\"); every reference in the project is inside the chokepoint","state":"invariant","enforces":["flushQueue"]},{"component":"src/lifecycle","name":"telemetry adds no wait to a hook","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:dd1946636d1e1820643272ec77f75ccca38660400796c3f27158e5ff427f77f8","at":"2026-10-27T22:15:41.516Z"},"testReferences":8,"files":["src/cli.ts","src/lifecycle/telemetry-cli.ts","src/lifecycle/telemetry.test.ts","src/lifecycle/telemetry.ts"],"latency":159,"reason":"flushQueue is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/lifecycle/telemetry.ts:564 reads \"export async function flushQueue(env: Env = process.env, sen\"); every reference in the project is inside the chokepoint; 8 test references","state":"invariant","enforces":["telemetryCommand"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sitesRef":{"hash":"sha256:4a8047712ca5f5301c05677c4094d28df614ad7b54617b994777be62306ff2f5","at":"2026-10-27T22:15:41.516Z"},"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":1934,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:855 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["ParseStore in src/plugins/syntax-trees.ts"]},{"component":"src/readings/scope","name":"fixed shell","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:8bab64ad785c80078a745befdd507e5eb3d46fb3fb0e0e937df0f3bc9b0bb60c","at":"2026-10-27T22:15:41.516Z"},"testReferences":1,"files":["src/enforcement/from.test.ts","src/lifecycle/lexicon-work.test.ts","src/readings/scope/build.ts","src/readings/scope/check.test.ts","src/readings/scope/live.test.ts","src/readings/scope/live.ts"],"latency":219,"reason":"loadState is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/readings/scope/build.ts:247 reads \"export async function loadState(options: BuildOptions): Prom\"); every reference in the project is inside the chokepoint; 1 test reference","state":"invariant","enforces":["scopeState"]},{"component":"src/scaffold","name":"every slot printed","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sitesRef":{"hash":"sha256:eb4d548e586d96f8f40dc00646f71d37c9722483c3717598f099a8b5d30a8ee5","at":"2026-10-27T22:15:41.516Z"},"testReferences":0,"files":["src/scaffold/boundaries.ts","src/scaffold/cli.ts","src/scaffold/control.ts","src/scaffold/scaffold.test.ts","src/scaffold/scaffold.ts"],"latency":1985,"reason":"PLACEHOLDERS is visibility-choked, enforced by the compiler: not visible outside its module (src/scaffold/scaffold.ts:119 declares PLACEHOLDERS without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["renderInvariant"]},{"component":"src/scaffold","name":"a component lives under its project","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sitesRef":{"hash":"sha256:4fa7253b352e6f6d159c6360d15a3afb8826cefc149937a466cf96c5bab1b3bb","at":"2026-10-27T22:15:41.516Z"},"testReferences":0,"files":["plugins/python/tach-boundaries.ts","src/plugins/api.ts","src/scaffold/boundaries.ts","src/scaffold/cli.ts","src/scaffold/control.ts","src/scaffold/import.ts","src/scaffold/scaffold.test.ts","src/scaffold/scaffold.ts"],"latency":827,"reason":"confineToRoot is visibility-choked, enforced by the compiler: not visible outside its module (src/scaffold/scaffold.ts:66 declares confineToRoot without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["src/scaffold/scaffold.ts"]},{"component":"src/spec","name":"retired sections refused","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:34c0fddd51fb55f9c2d1a9d58eb31efcc0de9a61fb71374416a7813f4231dbf8","at":"2026-10-27T22:15:41.516Z"},"testReferences":3,"files":["src/spec/grammar.ts","src/spec/spec.test.ts"],"latency":253,"reason":"RETIRED_SECTIONS is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/spec/grammar.ts:62 reads \"export const RETIRED_SECTIONS: readonly RetiredSection[] = (\"); every reference in the project is inside the chokepoint; 3 test references","state":"invariant","enforces":["retiredSection"]},{"component":"src/spec","name":"requirement until complete","form":"chokepoint","grade":"reference-choked","verdict":"pass","enforcer":"Coherence's check at the edit and in CI","from":{"value":"anywhere","by":"default"},"refutation":"automatic","bypasses":[],"sitesRef":{"hash":"sha256:b40cf59769eb99df2916889d10efbb685b88ce9f22399059f19404cb796ea5c9","at":"2026-10-27T22:15:41.516Z"},"testReferences":35,"files":["src/adapters/ignore-files.test.ts","src/economy/closure.ts","src/economy/mass.ts","src/enforcement/cli.ts","src/enforcement/enforcement.test.ts","src/enforcement/run.ts","src/journal/convergence.ts","src/journal/defects.test.ts","src/journal/verbs.ts","src/lifecycle/ci-report.ts","src/lifecycle/ci.test.ts","src/lifecycle/delivery.ts","src/lifecycle/hook.ts","src/lifecycle/mirrors.test.ts","src/lifecycle/practice-delivery.ts","src/lifecycle/project-name.test.ts","src/lifecycle/telemetry.ts","src/lifecycle/upgrade.test.ts","src/observation/observation.test.ts","src/plugins/convex.test.ts","src/plugins/languages.test.ts","src/plugins/plugins.test.ts","src/readings/scope/build.ts","src/readings/scope/component-interfaces.test.ts","src/readings/scope/component-interfaces.ts","src/readings/scope/gaps.ts","src/readings/scope/languages-read.test.ts","src/readings/scope/live.test.ts","src/readings/scope/multi-language.test.ts","src/readings/scope/structure-flow.test.ts","src/readings/scope/undeclared.ts","src/scaffold/cli.ts","src/scaffold/entrances.test.ts","src/scaffold/import.test.ts","src/scaffold/scaffold.test.ts","src/spec/cli.ts","src/spec/covers.test.ts","src/spec/dead-triggers.test.ts","src/spec/floor.test.ts","src/spec/model.ts","src/spec/practice.test.ts","src/spec/spec.test.ts","src/spec/state.ts"],"latency":364,"reason":"deriveState is reference-choked, enforced by Coherence's check at the edit and in CI: visible outside its module (src/spec/state.ts:68 reads \"export function deriveState(invariant: Invariant, applicable\"); every reference in the project is inside the chokepoint; 35 test references","state":"invariant","enforces":["loadSpecModel"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.714383b1.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.714383b1.jsonl new file mode 100644 index 00000000..d7f3f16c --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.714383b1.jsonl @@ -0,0 +1,17 @@ +{"at":"2026-10-26T19:01:39.899Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28893,"load":{"average":4.36,"cores":14},"batch":{"ms":28601},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28601,"reason":"1 test under \"a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":15,"mode":"batched","state":"requirement","enforces":["a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot"]},{"component":"src/plugins","name":"a parser reads a statement whole","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28601,"reason":"1 test under \"the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":8,"mode":"batched","state":"requirement","enforces":["the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28601,"reason":"1 test under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":54,"mode":"batched","state":"requirement","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"every tree is freed","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28601,"reason":"1 test under \"parses past the WebAssembly heap cliff all answer, a tree freed after each\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":7290,"mode":"batched","state":"requirement","enforces":["parses past the WebAssembly heap cliff all answer, a tree freed after each"]}]} +{"at":"2026-10-26T19:03:13.931Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":93757,"load":{"average":4.96,"cores":14},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21395,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot"]},{"component":"src/plugins","name":"a parser reads a statement whole","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21578,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads Python'\\''s imports and declarations whole: across lines, in blocks, never inside a string or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21679,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"every tree is freed","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":29076,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='parses past the WebAssembly heap cliff all answer, a tree freed after each' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["parses past the WebAssembly heap cliff all answer, a tree freed after each"]}]} +{"at":"2026-10-26T19:03:55.828Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":21957,"load":{"average":4.61,"cores":14},"batch":{"ms":21674},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21674,"reason":"1 of 1 tests under \"a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot\" failed: a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot","testMs":2,"mode":"batched","state":"requirement","enforces":["a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot"]}]} +{"kind":"refutation","at":"2026-10-26T19:03:56.112Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","broke":"let a manifest that names a parser fill source, declares, topLevel or kept beside it: the slots it would read a second time were never found (src/plugins/registry.ts treeSitterProblems)","verdict":"fail","reason":"1 of 1 tests under \"a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot\" failed: a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot","commit":"1aef204","dirty":true} +{"at":"2026-10-26T19:04:31.125Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":21903,"load":{"average":4.57,"cores":14},"batch":{"ms":21610},"invariants":[{"component":"src/plugins","name":"a parser reads a statement whole","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21610,"reason":"1 of 1 tests under \"the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment\" failed: the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment","testMs":14,"mode":"batched","state":"requirement","enforces":["the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment"]}]} +{"kind":"refutation","at":"2026-10-26T19:04:31.400Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser reads a statement whole","form":"totality oracle","broke":"had the source slot read a text's imports one line at a time through the parser, as Python's hand-written reader read them (src/plugins/languages.ts treeSlot source.importsOf)","verdict":"fail","reason":"1 of 1 tests under \"the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment\" failed: the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment","commit":"1aef204","dirty":true} +{"at":"2026-10-26T19:05:06.486Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":21930,"load":{"average":4.36,"cores":14},"batch":{"ms":21642},"invariants":[{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21642,"reason":"1 of 1 tests under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name\" failed: a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name","testMs":6,"mode":"batched","state":"requirement","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]}]} +{"kind":"refutation","at":"2026-10-26T19:05:06.768Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","broke":"let a query capture a name Coherence reads nothing by, passed over in silence (src/plugins/syntax-trees.ts buildReader)","verdict":"fail","reason":"1 of 1 tests under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name\" failed: a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name","commit":"1aef204","dirty":true} +{"at":"2026-10-26T19:05:29.519Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22167,"load":{"average":4.31,"cores":14},"batch":{"ms":21884},"invariants":[{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21884,"reason":"1 of 1 tests under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name\" failed: a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name","testMs":60,"mode":"batched","state":"requirement","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]}]} +{"kind":"refutation","at":"2026-10-26T19:05:29.789Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","broke":"let a reading build its parser before the process started the runtime, unchecked (src/plugins/syntax-trees.ts treeReaderOf)","verdict":"fail","reason":"1 of 1 tests under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name\" failed: a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name","commit":"1aef204","dirty":true} +{"at":"2026-10-26T19:06:08.277Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29789,"load":{"average":4.12,"cores":14},"batch":{"ms":29497},"invariants":[{"component":"src/plugins","name":"every tree is freed","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":29497,"reason":"1 test under \"parses past the WebAssembly heap cliff all answer, a tree freed after each\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":7365,"mode":"batched","state":"requirement","enforces":["parses past the WebAssembly heap cliff all answer, a tree freed after each"]}]} +{"at":"2026-10-26T19:07:24.136Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":21798,"load":{"average":3.95,"cores":14},"batch":{"ms":21497},"invariants":[{"component":"src/plugins","name":"every tree is freed","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21497,"reason":"1 test under \"every tree a reading parses is freed before the reading returns, none left to the collector\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":15,"mode":"batched","state":"requirement","enforces":["every tree a reading parses is freed before the reading returns, none left to the collector"]}]} +{"at":"2026-10-26T19:07:46.192Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":21789,"load":{"average":3.59,"cores":14},"invariants":[{"component":"src/plugins","name":"every tree is freed","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21761,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every tree a reading parses is freed before the reading returns, none left to the collector' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["every tree a reading parses is freed before the reading returns, none left to the collector"]}]} +{"at":"2026-10-26T19:08:08.949Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22161,"load":{"average":3.59,"cores":14},"batch":{"ms":21870},"invariants":[{"component":"src/plugins","name":"every tree is freed","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":21870,"reason":"1 of 1 tests under \"every tree a reading parses is freed before the reading returns, none left to the collector\" failed: every tree a reading parses is freed before the reading returns, none left to the collector","testMs":13,"mode":"batched","state":"requirement","enforces":["every tree a reading parses is freed before the reading returns, none left to the collector"]}]} +{"kind":"refutation","at":"2026-10-26T19:08:09.228Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"every tree is freed","form":"totality oracle","broke":"dropped tree.delete() after the matches are read, leaving each tree to the collector (src/plugins/syntax-trees.ts buildReader)","verdict":"fail","reason":"1 of 1 tests under \"every tree a reading parses is freed before the reading returns, none left to the collector\" failed: every tree a reading parses is freed before the reading returns, none left to the collector","commit":"1aef204","dirty":true} +{"at":"2026-10-26T19:08:36.169Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22274,"load":{"average":3.38,"cores":14},"batch":{"ms":21970},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21970,"reason":"1 test under \"a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":15,"mode":"batched","state":"invariant","enforces":["a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot"]},{"component":"src/plugins","name":"a parser reads a statement whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21970,"reason":"1 test under \"the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":8,"mode":"batched","state":"invariant","enforces":["the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21970,"reason":"1 test under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":57,"mode":"batched","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"every tree is freed","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21970,"reason":"1 test under \"every tree a reading parses is freed before the reading returns, none left to the collector\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["every tree a reading parses is freed before the reading returns, none left to the collector"]}]} +{"at":"2026-10-26T19:10:04.486Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":88046,"load":{"average":4.62,"cores":14},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21930,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot"]},{"component":"src/plugins","name":"a parser reads a statement whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21842,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads Python'\\''s imports and declarations whole: across lines, in blocks, never inside a string or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22094,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"every tree is freed","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22151,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every tree a reading parses is freed before the reading returns, none left to the collector' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["every tree a reading parses is freed before the reading returns, none left to the collector"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.89a170e0.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.89a170e0.jsonl new file mode 100644 index 00000000..97650b99 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.89a170e0.jsonl @@ -0,0 +1,28 @@ +{"at":"2026-10-27T19:10:34.477Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26056,"load":{"average":3.58,"cores":14},"batch":{"ms":25656},"invariants":[{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25656,"reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","testMs":240,"mode":"batched","state":"requirement","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]}]} +{"kind":"refutation","at":"2026-10-27T19:10:34.892Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","broke":"read a kept parse whatever its folder (ParseStore.get in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:11:06.742Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27261,"load":{"average":5.17,"cores":14},"batch":{"ms":26911},"invariants":[{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26911,"reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","testMs":320,"mode":"batched","state":"requirement","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]}]} +{"kind":"refutation","at":"2026-10-27T19:11:07.126Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","broke":"read a kept parse others may write (ownFile in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:11:34.914Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27160,"load":{"average":8,"cores":14},"batch":{"ms":26797},"invariants":[{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26797,"reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","testMs":397,"mode":"batched","state":"requirement","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]}]} +{"kind":"refutation","at":"2026-10-27T19:11:35.330Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","broke":"opened a kept parse following a link (ownFile in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:12:02.934Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26972,"load":{"average":7.43,"cores":14},"batch":{"ms":26608},"invariants":[{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26608,"reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","testMs":468,"mode":"batched","state":"requirement","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]}]} +{"kind":"refutation","at":"2026-10-27T19:12:03.254Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","broke":"checked the store's folder and the one it is in, none above (usersAlone in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:12:30.490Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26624,"load":{"average":7.42,"cores":14},"batch":{"ms":26271},"invariants":[{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26271,"reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","testMs":161,"mode":"batched","state":"requirement","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]}]} +{"kind":"refutation","at":"2026-10-27T19:12:30.811Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","broke":"checked the parses folder alone, never a fingerprint's (ParseStore.of in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:12:58.117Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26700,"load":{"average":7.35,"cores":14},"batch":{"ms":26346},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26346,"reason":"1 of 1 tests under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing\" failed: the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing","testMs":280,"mode":"batched","state":"structural defect","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing"]}]} +{"kind":"refutation","at":"2026-10-27T19:12:58.435Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","broke":"judged the cache's folders by the path as written, no link followed (usersAlone in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing\" failed: the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:13:25.681Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26635,"load":{"average":8.6,"cores":14},"batch":{"ms":26282},"invariants":[{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26282,"reason":"1 of 1 tests under \"a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made\" failed: a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made","testMs":212,"mode":"batched","state":"structural defect","enforces":["a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made"]}]} +{"kind":"refutation","at":"2026-10-27T19:13:26.102Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","broke":"kept every text's parse a reading met in memory, unbounded (readerOver in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made\" failed: a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:13:53.603Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26882,"load":{"average":9.65,"cores":14},"batch":{"ms":26519},"invariants":[{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26519,"reason":"1 of 1 tests under \"syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path\" failed: syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path","testMs":2,"mode":"batched","state":"requirement","enforces":["syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path"]}]} +{"kind":"refutation","at":"2026-10-27T19:13:53.997Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","broke":"exported parsesFolder through export { } (src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path\" failed: syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:14:21.775Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27167,"load":{"average":12.12,"cores":14},"batch":{"ms":26813},"invariants":[{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26813,"reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","testMs":240,"mode":"batched","state":"requirement","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"kind":"refutation","at":"2026-10-27T19:14:22.191Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","broke":"stamped no kept parse as read (ownFile in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:14:49.552Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26668,"load":{"average":10.59,"cores":14},"batch":{"ms":26300},"invariants":[{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26300,"reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","testMs":316,"mode":"batched","state":"requirement","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"kind":"refutation","at":"2026-10-27T19:14:49.964Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","broke":"swept at every warm-up, whatever the last sweep's time (ParseStore.sweep in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:15:17.248Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26651,"load":{"average":9.74,"cores":14},"batch":{"ms":26266},"invariants":[{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26266,"reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","testMs":245,"mode":"batched","state":"requirement","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"kind":"refutation","at":"2026-10-27T19:15:17.671Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","broke":"swept a write's temporary file at once, however young (ParseStore.sweep in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:15:45.142Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26854,"load":{"average":9.64,"cores":14},"batch":{"ms":26494},"invariants":[{"component":"src/plugins","name":"two warm-ups at once need no lock","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26494,"reason":"1 of 1 tests under \"two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it\" failed: two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it","testMs":174,"mode":"batched","state":"requirement","enforces":["two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it"]}]} +{"kind":"refutation","at":"2026-10-27T19:15:45.530Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"two warm-ups at once need no lock","form":"totality oracle","broke":"held a second warm-up off while one runs, as the warm-up lock did (warmParses in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it\" failed: two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:16:19.472Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":33477,"load":{"average":8.71,"cores":14},"batch":{"ms":33083},"invariants":[{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":33083,"reason":"1 of 1 tests under \"Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in\" failed: Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in","testMs":3,"mode":"batched","state":"structural defect","enforces":["Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in"]}]} +{"kind":"refutation","at":"2026-10-27T19:16:20.492Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","broke":"took a relative XDG_CACHE_HOME (userCacheDir in src/lifecycle/user-dir.ts)","verdict":"fail","reason":"1 of 1 tests under \"Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in\" failed: Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:18:47.751Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":31779,"load":{"average":25.43,"cores":14},"batch":{"ms":30200},"invariants":[{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":356,"mode":"batched","state":"invariant","enforces":["a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":465,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":617,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":269,"mode":"batched","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":474,"mode":"batched","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":329,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":297,"mode":"batched","state":"invariant","enforces":["a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":135,"symbol":"readers.store","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":201,"symbol":"treeReaderOf","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":217,"symbol":"warmParses.reader.store","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":253,"symbol":"warmParses","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":273,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":436,"symbol":"readerOver","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":436,"symbol":"readerOver","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":543,"symbol":"ParseStore.stores","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":555,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":556,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":557,"symbol":"ParseStore.of.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":564,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":564,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":566,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":604,"symbol":"ParseStore.discard","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":620,"symbol":"ParseStore.sweep.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":653,"symbol":"ParseStore.writeAudit.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":666,"symbol":"ParseStore.audits.parses","class":"inside","of":"protected","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":733,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:687 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["ParseStore in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":0,"mode":"batched","state":"invariant","enforces":["syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":316,"mode":"batched","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]},{"component":"src/plugins","name":"two warm-ups at once need no lock","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":237,"mode":"batched","state":"invariant","enforces":["two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it"]},{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30200,"reason":"1 test under \"a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":130,"mode":"batched","state":"invariant","enforces":["a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept"]}]} +{"at":"2026-10-27T19:24:21.171Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":332951,"load":{"average":12.64,"cores":14},"invariants":[{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26215,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='Coherence'\\''s folders in the user'\\''s configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/\\.config and ~/\\.cache under a home that is absolute, HOME'\\''s, the account'\\''s or Node'\\''s, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25998,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a project'\\''s parses are kept between processes, in the user'\\''s cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26362,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26290,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32701,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store lives outside every project and is used only where the user'\\''s cache is the user'\\''s alone: a project'\\''s own \\.coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":45451,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is read only where it is the user'\\''s alone: a store folder, or a kept parse'\\''s folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26409,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24431,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24592,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='syntax-trees\\.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24176,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint'\\''s folder; one read since is kept' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]},{"component":"src/plugins","name":"two warm-ups at once need no lock","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25219,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='two warm-ups of one project at once both read every text, need no lock, and keep each text'\\''s parse once, whole and as a fresh parse reads it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it"]},{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25066,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a registry'\\''s leaves and its top share the user'\\''s one parse store: a warm-up of one leaf pre-reads the leaf and the top'\\''s files, and a warm-up of another reads what the first kept' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a16160ab.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a16160ab.jsonl new file mode 100644 index 00000000..29bb83bf --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a16160ab.jsonl @@ -0,0 +1,50 @@ +{"at":"2026-10-27T21:03:13.725Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25691,"load":{"average":5.72,"cores":14},"batch":{"ms":25304},"invariants":[{"component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25304,"reason":"1 of 1 tests under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" failed: a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name","testMs":161,"mode":"batched","state":"requirement","enforces":["a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name"]}]} +{"kind":"refutation","at":"2026-10-27T21:03:14.039Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","broke":"evaluated no #not-parent-type?, every match kept (matchesOf in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" failed: a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:03:44.469Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25722,"load":{"average":6.42,"cores":14},"batch":{"ms":25381},"invariants":[{"component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25381,"reason":"1 of 1 tests under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" failed: a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name","testMs":240,"mode":"batched","state":"requirement","enforces":["a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name"]}]} +{"kind":"refutation","at":"2026-10-27T21:03:44.781Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","broke":"kept a @misread match from a tree with an error (Compiled.parse in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" failed: a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:04:15.145Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25696,"load":{"average":6.43,"cores":14},"batch":{"ms":25364},"invariants":[{"component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25364,"reason":"1 of 1 tests under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" failed: a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name","testMs":252,"mode":"batched","state":"requirement","enforces":["a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name"]}]} +{"kind":"refutation","at":"2026-10-27T21:04:15.464Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","broke":"passed over a predicate nothing evaluates, as web-tree-sitter does (load in compile, src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" failed: a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:04:45.560Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25593,"load":{"average":5.08,"cores":14},"batch":{"ms":25260},"invariants":[{"component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25260,"reason":"1 of 1 tests under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" failed: a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name","testMs":81,"mode":"batched","state":"requirement","enforces":["a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name"]}]} +{"kind":"refutation","at":"2026-10-27T21:04:45.887Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","broke":"left no misread for orient (readerOver in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" failed: a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:05:16.017Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25475,"load":{"average":4.47,"cores":14},"batch":{"ms":25128},"invariants":[{"component":"src/plugins","name":"the TypeScript plugin's misread query names no valid form","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25128,"reason":"1 of 1 tests under \"the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines\" failed: the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines","testMs":58,"mode":"batched","state":"requirement","enforces":["the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines"]}]} +{"kind":"refutation","at":"2026-10-27T21:05:16.331Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the TypeScript plugin's misread query names no valid form","form":"totality oracle","broke":"dropped the exemption of an import's or an export's name from @misread (plugins/typescript/typescript.scm)","verdict":"fail","reason":"1 of 1 tests under \"the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines\" failed: the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:06:03.123Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":34509,"load":{"average":4.9,"cores":14},"batch":{"ms":31784},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31784,"reason":"7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":11879,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31784,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":65,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31784,"reason":"1 test under \"the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":2,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]},{"component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31784,"reason":"1 test under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":255,"mode":"batched","state":"invariant","enforces":["a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name"]},{"component":"src/plugins","name":"the TypeScript plugin's misread query names no valid form","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31784,"reason":"1 test under \"the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":99,"mode":"batched","state":"invariant","enforces":["the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":84,"symbol":"KeptReader","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":213,"symbol":"treeReaderOf","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":265,"symbol":"warmParses","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":286,"symbol":"misreadNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":301,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":482,"symbol":"readerOver","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":499,"symbol":"readerOver.read","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":592,"symbol":"ParseStore.stores","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":604,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":605,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":606,"symbol":"ParseStore.of.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":613,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":613,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":615,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":653,"symbol":"ParseStore.discard","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":669,"symbol":"ParseStore.sweep.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":702,"symbol":"ParseStore.writeAudit.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":715,"symbol":"ParseStore.writeMisread.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":727,"symbol":"ParseStore.misreads.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":744,"symbol":"ParseStore.audits.parses","class":"inside","of":"protected","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":704,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:765 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["ParseStore in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31784,"reason":"1 test under \"syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"invariant","enforces":["syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path"]}]} +{"at":"2026-10-27T21:08:41.766Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":158321,"load":{"average":5.92,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32116,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25372,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24896,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers\\.sha256 records, which the build phase checks its build against' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]},{"component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25101,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a word a plugin'\\''s queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name"]},{"component":"src/plugins","name":"the TypeScript plugin's misread query names no valid form","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25514,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the TypeScript plugin'\\''s queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import'\\''s or an export'\\''s name, export \\* as, and in, instanceof, typeof, labels and members across lines' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25283,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='syntax-trees\\.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path"]}]} +{"at":"2026-10-27T21:30:02.007Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":33344,"load":{"average":7.78,"cores":14},"batch":{"ms":32898},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32898,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":666,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32898,"reason":"1 test under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":3357,"mode":"batched","state":"requirement","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]},{"component":"src/plugins","name":"spelling prefixes costs what the nesting does","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32898,"reason":"1 test under \"spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":330,"mode":"batched","state":"requirement","enforces":["spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32898,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":687,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32898,"reason":"1 test under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":269,"mode":"batched","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32898,"reason":"1 test under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":771,"mode":"batched","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a store inside the repository is never used for it","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32898,"reason":"1 test under \"a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":173,"mode":"batched","state":"requirement","enforces":["a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32898,"reason":"1 test under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":338,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32898,"reason":"1 test under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":554,"mode":"batched","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"at":"2026-10-27T21:34:20.807Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":258398,"load":{"average":9.18,"cores":14},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27335,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":52071,"reason":"passed in the batched invocation, failed in its own: node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 1","mode":"one-at-a-time","state":"requirement","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]},{"component":"src/plugins","name":"spelling prefixes costs what the nesting does","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25617,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spelling an import'\\''s prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25782,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25170,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store lives outside every project and is used only where the user'\\''s cache is the user'\\''s alone: a project'\\''s own \\.coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25987,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is read only where it is the user'\\''s alone: a store folder, or a kept parse'\\''s folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a store inside the repository is never used for it","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25463,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository'\\''s top or a leaf below it read' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25447,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25488,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint'\\''s folder; one read since is kept' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"at":"2026-10-27T21:35:11.864Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28607,"load":{"average":9.96,"cores":14},"batch":{"ms":28194},"invariants":[{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28194,"reason":"1 of 1 tests under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" failed: a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read","testMs":3291,"mode":"batched","state":"requirement","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]}]} +{"kind":"refutation","at":"2026-10-27T21:35:12.287Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","broke":"left a parse cut short to resume at the next (bounded in compile, src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" failed: a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:36:20.887Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":42556,"load":{"average":9.33,"cores":14},"batch":{"ms":42220},"invariants":[{"component":"src/plugins","name":"spelling prefixes costs what the nesting does","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":42220,"reason":"1 of 1 tests under \"spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds\" failed: spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds","testMs":17582,"mode":"batched","state":"requirement","enforces":["spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds"]}]} +{"kind":"refutation","at":"2026-10-27T21:36:21.308Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"spelling prefixes costs what the nesting does","form":"totality oracle","broke":"scanned every prefix the file holds for each specifier, as before (speller in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds\" failed: spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:36:56.637Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25530,"load":{"average":10.05,"cores":14},"batch":{"ms":25185},"invariants":[{"component":"src/plugins","name":"a store inside the repository is never used for it","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25185,"reason":"1 of 1 tests under \"a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read\" failed: a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read","testMs":100,"mode":"batched","state":"requirement","enforces":["a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read"]}]} +{"kind":"refutation","at":"2026-10-27T21:36:56.957Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a store inside the repository is never used for it","form":"totality oracle","broke":"used a store wherever it lies (ParseStore.outside in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read\" failed: a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:37:32.357Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26063,"load":{"average":9.62,"cores":14},"batch":{"ms":25716},"invariants":[{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25716,"reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","testMs":619,"mode":"batched","state":"structural defect","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]}]} +{"kind":"refutation","at":"2026-10-27T21:37:32.668Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","broke":"judged the store's path only as followed, never as written (whyNotUsersAlone in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:38:08.754Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26381,"load":{"average":12.9,"cores":14},"batch":{"ms":26034},"invariants":[{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26034,"reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","testMs":805,"mode":"batched","state":"structural defect","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]}]} +{"kind":"refutation","at":"2026-10-27T21:38:09.162Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","broke":"read a kept parse of any size (ownFile in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:38:44.872Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26366,"load":{"average":14.77,"cores":14},"batch":{"ms":26021},"invariants":[{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26021,"reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","testMs":538,"mode":"batched","state":"structural defect","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]}]} +{"kind":"refutation","at":"2026-10-27T21:38:45.283Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","broke":"said nothing when the store is off (parserNotice in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" failed: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:39:20.621Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25936,"load":{"average":12.6,"cores":14},"batch":{"ms":25595},"invariants":[{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25595,"reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","testMs":393,"mode":"batched","state":"structural defect","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"kind":"refutation","at":"2026-10-27T21:39:20.952Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","broke":"took a sweep dated ahead as one within the day (ParseStore.sweep in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:39:55.890Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25670,"load":{"average":9.58,"cores":14},"batch":{"ms":25324},"invariants":[{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25324,"reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","testMs":246,"mode":"batched","state":"structural defect","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"kind":"refutation","at":"2026-10-27T21:39:56.210Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","broke":"swept temporary files in shards alone (ParseStore.sweep in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:40:31.958Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26169,"load":{"average":7.93,"cores":14},"batch":{"ms":25805},"invariants":[{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25805,"reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","testMs":555,"mode":"batched","state":"structural defect","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"kind":"refutation","at":"2026-10-27T21:40:32.384Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","broke":"let a stamp that cannot be written fail the read (ownFile in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" failed: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:41:07.925Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25917,"load":{"average":7.06,"cores":14},"batch":{"ms":25563},"invariants":[{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25563,"reason":"1 of 1 tests under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" failed: a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week","testMs":685,"mode":"batched","state":"structural defect","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]}]} +{"kind":"refutation","at":"2026-10-27T21:41:08.242Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","broke":"sampled the first eight kept texts of the pass (warmParses in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" failed: a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:41:43.471Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25774,"load":{"average":6.32,"cores":14},"batch":{"ms":25430},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25430,"reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","testMs":576,"mode":"batched","state":"structural defect","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]}]} +{"kind":"refutation","at":"2026-10-27T21:41:43.774Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","broke":"left the web-tree-sitter release out of the fingerprint (fingerprintOf in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:42:19.095Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25858,"load":{"average":6.19,"cores":14},"batch":{"ms":25512},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25512,"reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","testMs":639,"mode":"batched","state":"structural defect","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]}]} +{"kind":"refutation","at":"2026-10-27T21:42:19.418Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","broke":"left the module's own source out of the fingerprint (fingerprintOf in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:42:54.384Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25571,"load":{"average":6.77,"cores":14},"batch":{"ms":25228},"invariants":[{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25228,"reason":"1 of 1 tests under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" failed: a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes","testMs":371,"mode":"batched","state":"structural defect","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]}]} +{"kind":"refutation","at":"2026-10-27T21:42:54.703Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","broke":"read a file whatever folder its path passes through (warmText in src/economy/warm-parses.ts)","verdict":"fail","reason":"1 of 1 tests under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" failed: a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:46:57.276Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":41216,"load":{"average":15.69,"cores":14},"batch":{"ms":40308},"invariants":[{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":40308,"reason":"1 of 1 tests under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" failed: a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read","testMs":6002,"mode":"batched","state":"requirement","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]}]} +{"kind":"refutation","at":"2026-10-27T21:46:57.689Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","broke":"spent no bound on a parse (bounded in compile, src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" failed: a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:47:52.579Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":45186,"load":{"average":16.97,"cores":14},"batch":{"ms":44802},"invariants":[{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":44802,"reason":"1 of 1 tests under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" failed: a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read","testMs":8407,"mode":"batched","state":"requirement","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]}]} +{"kind":"refutation","at":"2026-10-27T21:47:53.465Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","broke":"left a parse cut short to resume at the next (bounded in compile, src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" failed: a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:48:38.539Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29800,"load":{"average":52.19,"cores":14},"batch":{"ms":29461},"invariants":[{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29461,"reason":"1 of 1 tests under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" failed: a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read","testMs":4451,"mode":"batched","state":"requirement","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]}]} +{"kind":"refutation","at":"2026-10-27T21:48:38.933Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","broke":"spent no bound on a query (matchesOf in compile, src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" failed: a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:49:48.816Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":53260,"load":{"average":26.04,"cores":14},"batch":{"ms":52812},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52812,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":1193,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52812,"reason":"1 test under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":4150,"mode":"batched","state":"invariant","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]},{"component":"src/plugins","name":"spelling prefixes costs what the nesting does","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52812,"reason":"1 test under \"spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":331,"mode":"batched","state":"invariant","enforces":["spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52812,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":1258,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52812,"reason":"1 test under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":387,"mode":"batched","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52812,"reason":"1 test under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":951,"mode":"batched","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a store inside the repository is never used for it","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52812,"reason":"1 test under \"a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":229,"mode":"batched","state":"invariant","enforces":["a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52812,"reason":"1 test under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":510,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52812,"reason":"1 test under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<9 names> src/**/*.test.ts src/*.e2e.ts","testMs":547,"mode":"batched","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"at":"2026-10-27T21:53:35.873Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":226652,"load":{"average":5.56,"cores":14},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25216,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28515,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]},{"component":"src/plugins","name":"spelling prefixes costs what the nesting does","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24413,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spelling an import'\\''s prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24762,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24307,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store lives outside every project and is used only where the user'\\''s cache is the user'\\''s alone: a project'\\''s own \\.coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24814,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is read only where it is the user'\\''s alone: a store folder, or a kept parse'\\''s folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a store inside the repository is never used for it","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24797,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository'\\''s top or a leaf below it read' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24803,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24985,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint'\\''s folder; one read since is kept' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]}]} +{"at":"2026-10-27T21:57:46.202Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":38817,"load":{"average":7.75,"cores":14},"batch":{"ms":37400},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":403,"mode":"batched","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":1217,"mode":"batched","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/lifecycle","name":"no totals are injected","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"no hook injection carries a total: orient names the ranked terms or says nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":685,"mode":"batched","state":"invariant","enforces":["no hook injection carries a total: orient names the ranked terms or says nothing"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":68,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":2,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":663,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":3927,"mode":"batched","state":"invariant","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]},{"component":"src/plugins","name":"spelling prefixes costs what the nesting does","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":321,"mode":"batched","state":"invariant","enforces":["spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds"]},{"component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":248,"mode":"batched","state":"invariant","enforces":["a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name"]},{"component":"src/plugins","name":"the TypeScript plugin's misread query names no valid form","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":2,"mode":"batched","state":"invariant","enforces":["the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":674,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":774,"mode":"batched","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a store inside the repository is never used for it","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":167,"mode":"batched","state":"invariant","enforces":["a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":336,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":85,"symbol":"KeptReader","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":215,"symbol":"treeReaderOf.store","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":278,"symbol":"warmParses","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":304,"symbol":"parserNotice.misreads","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":307,"symbol":"parserNotice.unreads","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":324,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":534,"symbol":"readerOver","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":547,"symbol":"readerOver.read","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":554,"symbol":"readerOver.read","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":647,"symbol":"ParseStore.stores","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":659,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":660,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":661,"symbol":"ParseStore.of.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":668,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":668,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":670,"symbol":"ParseStore.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":710,"symbol":"ParseStore.discard","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":754,"symbol":"ParseStore.sweep.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":792,"symbol":"ParseStore.writeAudit.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":805,"symbol":"ParseStore.writeNote.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":817,"symbol":"ParseStore.notes.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":834,"symbol":"ParseStore.audits.parses","class":"inside","of":"protected","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":645,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:855 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["ParseStore in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":0,"mode":"batched","state":"invariant","enforces":["syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":538,"mode":"batched","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]},{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":21,"mode":"batched","state":"invariant","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":2050,"mode":"batched","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37400,"reason":"1 test under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<19 names> src/**/*.test.ts src/*.e2e.ts","testMs":1025,"mode":"batched","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"at":"2026-10-27T22:05:37.090Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":470570,"load":{"average":5.26,"cores":14},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24307,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24909,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/lifecycle","name":"no totals are injected","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24375,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='no hook injection carries a total: orient names the ranked terms or says nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["no hook injection carries a total: orient names the ranked terms or says nothing"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23704,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23701,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers\\.sha256 records, which the build phase checks its build against' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24269,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a reading spends bounded work on one text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27905,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read"]},{"component":"src/plugins","name":"spelling prefixes costs what the nesting does","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24441,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spelling an import'\\''s prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds"]},{"component":"src/plugins","name":"a parser's misread is said at orient","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24525,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a word a plugin'\\''s queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name"]},{"component":"src/plugins","name":"the TypeScript plugin's misread query names no valid form","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24335,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the TypeScript plugin'\\''s queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import'\\''s or an export'\\''s name, export \\* as, and in, instanceof, typeof, labels and members across lines' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25552,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"a kept parse is read only where it is the user's alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25803,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is read only where it is the user'\\''s alone: a store folder, or a kept parse'\\''s folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed"]},{"component":"src/plugins","name":"a store inside the repository is never used for it","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24487,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository'\\''s top or a leaf below it read' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24436,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"the parse store is reached only inside its module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24053,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='syntax-trees\\.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path"]},{"component":"src/plugins","name":"a kept parse no process reads is swept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24577,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint'\\''s folder; one read since is kept' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept"]},{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24039,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26099,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human'\\''s acknowledgement answers it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25005,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl new file mode 100644 index 00000000..9e13ffae --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a238a4ee.jsonl @@ -0,0 +1,24 @@ +{"at":"2026-10-26T22:48:10.016Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28314,"load":{"average":5.51,"cores":14},"batch":{"ms":27720},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":27720,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":128,"mode":"batched","state":"requirement","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]}]} +{"at":"2026-10-26T22:48:35.800Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25449,"load":{"average":5,"cores":14},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25225,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]}]} +{"at":"2026-10-26T22:49:03.571Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26970,"load":{"average":5,"cores":14},"batch":{"ms":26402},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26402,"reason":"1 of 1 tests under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" failed: the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed","testMs":17,"mode":"batched","state":"requirement","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]}]} +{"kind":"refutation","at":"2026-10-26T22:49:03.947Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","broke":"made the store's path check pass whatever lies on the path, links among it (src/plugins/syntax-trees.ts ParseStore.safe)","verdict":"fail","reason":"1 of 1 tests under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" failed: the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed","commit":"8d78643","dirty":true} +{"at":"2026-10-26T22:49:32.125Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27583,"load":{"average":5.66,"cores":14},"batch":{"ms":26987},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26987,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":105,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]}]} +{"at":"2026-10-26T22:49:59.685Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27217,"load":{"average":11.46,"cores":14},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26986,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]}]} +{"at":"2026-10-26T22:52:30.218Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24864,"load":{"average":5.42,"cores":14},"batch":{"ms":24376},"invariants":[{"component":"src/plugins","name":"a whole-module import reaches a reference name only where the importer spells it","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24376,"reason":"1 test under \"a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":69,"mode":"batched","state":"requirement","enforces":["a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them"]}]} +{"at":"2026-10-26T22:52:54.707Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24177,"load":{"average":5.73,"cores":14},"invariants":[{"component":"src/plugins","name":"a whole-module import reaches a reference name only where the importer spells it","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24031,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them"]}]} +{"at":"2026-10-26T22:53:20.092Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24686,"load":{"average":5.73,"cores":14},"batch":{"ms":24283},"invariants":[{"component":"src/plugins","name":"a whole-module import reaches a reference name only where the importer spells it","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24283,"reason":"1 of 1 tests under \"a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them\" failed: a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them","testMs":55,"mode":"batched","state":"requirement","enforces":["a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them"]}]} +{"kind":"refutation","at":"2026-10-26T22:53:20.401Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a whole-module import reaches a reference name only where the importer spells it","form":"totality oracle","broke":"let a whole-module import reach every name whether the importer spells it or not, as before (src/plugins/check.ts referenceRelations)","verdict":"fail","reason":"1 of 1 tests under \"a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them\" failed: a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them","commit":"8d78643","dirty":true} +{"at":"2026-10-26T22:53:45.762Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24742,"load":{"average":5.94,"cores":14},"batch":{"ms":24321},"invariants":[{"component":"src/plugins","name":"a whole-module import reaches a reference name only where the importer spells it","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24321,"reason":"1 test under \"a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":70,"mode":"batched","state":"invariant","enforces":["a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them"]}]} +{"at":"2026-10-26T22:54:10.446Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24375,"load":{"average":5.74,"cores":14},"invariants":[{"component":"src/plugins","name":"a whole-module import reaches a reference name only where the importer spells it","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24270,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them"]}]} +{"at":"2026-10-26T22:57:10.912Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27882,"load":{"average":4.5,"cores":14},"batch":{"ms":27248},"invariants":[{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":27248,"reason":"1 test under \"a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":22,"mode":"batched","state":"requirement","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]}]} +{"at":"2026-10-26T22:57:38.952Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27696,"load":{"average":5.69,"cores":14},"invariants":[{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":27465,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]}]} +{"at":"2026-10-26T22:58:07.680Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27934,"load":{"average":5.69,"cores":14},"batch":{"ms":27363},"invariants":[{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":27363,"reason":"1 of 1 tests under \"a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3\" failed: a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3","testMs":25,"mode":"batched","state":"requirement","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]}]} +{"kind":"refutation","at":"2026-10-26T22:58:08.031Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","broke":"held every plugin to the reference reading and server agrees whatever pluginApi it is written for (src/plugins/check.ts notHeld)","verdict":"fail","reason":"1 of 1 tests under \"a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3\" failed: a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3","commit":"8d78643","dirty":true} +{"at":"2026-10-26T22:58:40.779Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":32122,"load":{"average":5.36,"cores":14},"batch":{"ms":31492},"invariants":[{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31492,"reason":"1 test under \"a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":21,"mode":"batched","state":"invariant","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]}]} +{"at":"2026-10-26T22:59:08.996Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27863,"load":{"average":5.71,"cores":14},"invariants":[{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27633,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]}]} +{"at":"2026-10-26T23:01:03.215Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25887,"load":{"average":6.09,"cores":14},"batch":{"ms":25255},"invariants":[{"component":"src/plugins","name":"a TypeScript re-export is an import of what it re-exports","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25255,"reason":"1 test under \"a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":30,"mode":"batched","state":"requirement","enforces":["a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace"]}]} +{"at":"2026-10-26T23:01:29.978Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26367,"load":{"average":6.33,"cores":14},"invariants":[{"component":"src/plugins","name":"a TypeScript re-export is an import of what it re-exports","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26148,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace"]}]} +{"at":"2026-10-26T23:01:57.805Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27051,"load":{"average":6.33,"cores":14},"batch":{"ms":26500},"invariants":[{"component":"src/plugins","name":"a TypeScript re-export is an import of what it re-exports","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26500,"reason":"1 of 1 tests under \"a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace\" failed: a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace","testMs":29,"mode":"batched","state":"requirement","enforces":["a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace"]}]} +{"kind":"refutation","at":"2026-10-26T23:01:58.137Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a TypeScript re-export is an import of what it re-exports","form":"totality oracle","broke":"made the source scan read no re-export, as before (plugins/typescript/typescript-source.ts)","verdict":"fail","reason":"1 of 1 tests under \"a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace\" failed: a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace","commit":"8d78643","dirty":true} +{"at":"2026-10-26T23:02:25.860Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27144,"load":{"average":5.72,"cores":14},"batch":{"ms":26572},"invariants":[{"component":"src/plugins","name":"a TypeScript re-export is an import of what it re-exports","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26572,"reason":"1 test under \"a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":28,"mode":"batched","state":"invariant","enforces":["a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace"]}]} +{"at":"2026-10-26T23:02:54.318Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"8d78643","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28114,"load":{"average":6.68,"cores":14},"invariants":[{"component":"src/plugins","name":"a TypeScript re-export is an import of what it re-exports","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27859,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a42bdfe5.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a42bdfe5.jsonl new file mode 100644 index 00000000..b8a05af5 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.a42bdfe5.jsonl @@ -0,0 +1,24 @@ +{"at":"2026-10-27T03:46:40.321Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23817,"load":{"average":3.77,"cores":14},"batch":{"ms":23504},"invariants":[{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23504,"reason":"1 of 1 tests under \"a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size\" failed: a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size","testMs":173,"mode":"batched","state":"requirement","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]}]} +{"kind":"refutation","at":"2026-10-27T03:46:40.615Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","broke":"read every log line whatever its signature (ParseStore.get in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size\" failed: a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:47:05.377Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24198,"load":{"average":3.52,"cores":14},"batch":{"ms":23880},"invariants":[{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23880,"reason":"1 of 1 tests under \"a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size\" failed: a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size","testMs":330,"mode":"batched","state":"requirement","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]}]} +{"kind":"refutation","at":"2026-10-27T03:47:05.642Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","broke":"read a log on past every line that fails its signature, with no bound (ParseStore.get in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size\" failed: a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:47:31.892Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25659,"load":{"average":3.25,"cores":14},"batch":{"ms":25341},"invariants":[{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25341,"reason":"1 of 1 tests under \"a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" failed: a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced","testMs":1423,"mode":"batched","state":"requirement","enforces":["a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]}]} +{"kind":"refutation","at":"2026-10-27T03:47:32.199Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","broke":"let a process's own append restamp the store it loaded, whatever another process did since (ParseStore.flush in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" failed: a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:48:18.226Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":45459,"load":{"average":3.66,"cores":14},"batch":{"ms":45147},"invariants":[{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":45147,"reason":"1 of 1 tests under \"a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" failed: a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced","testMs":21453,"mode":"batched","state":"requirement","enforces":["a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]}]} +{"kind":"refutation","at":"2026-10-27T03:48:18.506Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","broke":"opened the log to append without O_NONBLOCK (ParseStore.flush in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" failed: a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:48:44.369Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25306,"load":{"average":3.56,"cores":14},"batch":{"ms":25000},"invariants":[{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25000,"reason":"1 of 1 tests under \"a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" failed: a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced","testMs":1775,"mode":"batched","state":"requirement","enforces":["a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]}]} +{"kind":"refutation","at":"2026-10-27T03:48:44.660Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","broke":"kept a key file too short to be a key in place (machineKey in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" failed: a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:49:08.751Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23533,"load":{"average":4.34,"cores":14},"batch":{"ms":23212},"invariants":[{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23212,"reason":"1 of 1 tests under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" failed: a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said","testMs":17,"mode":"batched","state":"structural defect","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]}]} +{"kind":"refutation","at":"2026-10-27T03:49:09.046Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","broke":"let a folder or a link at the lock's path hold the warm-up off (ParseStore.lock in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" failed: a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:49:32.274Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22693,"load":{"average":4.42,"cores":14},"batch":{"ms":22393},"invariants":[{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22393,"reason":"1 of 1 tests under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" failed: the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment","testMs":122,"mode":"batched","state":"structural defect","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]}]} +{"kind":"refutation","at":"2026-10-27T03:49:32.553Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","broke":"chose between the parser's tree and the alternate's by how many errors each holds (errorSpan in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" failed: the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:49:55.760Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22684,"load":{"average":3.95,"cores":14},"batch":{"ms":22387},"invariants":[{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22387,"reason":"1 of 1 tests under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name\" failed: a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name","testMs":21,"mode":"batched","state":"structural defect","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name"]}]} +{"kind":"refutation","at":"2026-10-27T03:49:56.033Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","broke":"compiled the alternate parser up front, as 45d4538 did (compile in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name\" failed: a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:50:19.270Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22699,"load":{"average":3.72,"cores":14},"batch":{"ms":22405},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22405,"reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","testMs":6,"mode":"batched","state":"structural defect","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]}]} +{"kind":"refutation","at":"2026-10-27T03:50:19.563Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","broke":"filed the alternate parser under its name, not its bytes (fingerprintOf in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:52:06.030Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22344,"load":{"average":4.17,"cores":14},"batch":{"ms":21993},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21993,"reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it","testMs":59,"mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]}]} +{"kind":"refutation","at":"2026-10-27T03:52:06.283Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","broke":"built the parsers from e8f802e's patch, which read every character past ASCII as part of a name, a member named instanceof as the operator, and a bare & before a JSX string's quote as taking the quote","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:52:33.265Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22446,"load":{"average":4.31,"cores":14},"batch":{"ms":22158},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22158,"reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it","testMs":61,"mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]}]} +{"kind":"refutation","at":"2026-10-27T03:52:33.538Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","broke":"built the parsers with a JSX text scanner that tells no character reference apart, so & reads as text (common/scanner.h in grammars/tree-sitter-typescript/coherence.patch)","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it","commit":"e8f802e","dirty":true} +{"at":"2026-10-27T03:56:37.534Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25146,"load":{"average":3.25,"cores":14},"batch":{"ms":24652},"invariants":[{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24652,"reason":"1 test under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":122,"mode":"batched","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24652,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":4,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24652,"reason":"1 test under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":68,"mode":"batched","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24652,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":398,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24652,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":81,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24652,"reason":"1 test under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":4,"mode":"batched","state":"invariant","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24652,"reason":"1 test under \"a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":284,"mode":"batched","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24652,"reason":"1 test under \"a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":1729,"mode":"batched","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]}]} +{"at":"2026-10-27T03:59:41.808Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"e8f802e","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":183911,"load":{"average":6.32,"cores":14},"invariants":[{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22121,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads TypeScript'\\''s imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22253,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22340,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22884,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22536,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23008,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store'\\''s file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24168,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a log line is read only where it signs itself with this machine'\\''s key, a torn line is passed over, and a log that fails more than a torn line'\\''s worth is read no further, so a repository'\\''s log costs a few signatures whatever its size' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24554,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log'\\''s path never holds a process up, and a key file too short to be one is replaced' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.ae0f5949.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.ae0f5949.jsonl new file mode 100644 index 00000000..cbaccfc8 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.ae0f5949.jsonl @@ -0,0 +1,10 @@ +{"at":"2026-10-27T00:12:41.539Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"a3bdbc1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25553,"load":{"average":12.43,"cores":14},"batch":{"ms":25069},"invariants":[{"component":"src/plugins","name":"Go is read through its parser","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25069,"reason":"1 test under \"a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":15,"mode":"batched","state":"invariant","enforces":["a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25069,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":273,"mode":"batched","state":"requirement","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25069,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":501,"mode":"batched","state":"requirement","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]}]} +{"at":"2026-10-27T00:13:53.371Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"a3bdbc1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":71533,"load":{"average":5.77,"cores":14},"invariants":[{"component":"src/plugins","name":"Go is read through its parser","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23682,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string \\(a package clause in one among it\\) declare nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23798,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24022,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]}]} +{"at":"2026-10-27T00:14:29.250Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"a3bdbc1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24084,"load":{"average":5.12,"cores":14},"batch":{"ms":23768},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23768,"reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","testMs":52,"mode":"batched","state":"requirement","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]}]} +{"kind":"refutation","at":"2026-10-27T00:14:29.535Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","broke":"left the separator out of the fingerprint (KEPT_FROM in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","commit":"a3bdbc1","dirty":true} +{"at":"2026-10-27T00:14:55.441Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"a3bdbc1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25381,"load":{"average":5.13,"cores":14},"batch":{"ms":25060},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25060,"reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","testMs":267,"mode":"batched","state":"requirement","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]}]} +{"kind":"refutation","at":"2026-10-27T00:14:55.735Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","broke":"imported PLUGIN_API from plugin.ts at run time in syntax-trees.ts, code outside the digested module","verdict":"fail","reason":"1 of 1 tests under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" failed: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone","commit":"a3bdbc1","dirty":true} +{"at":"2026-10-27T00:15:20.670Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"a3bdbc1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24413,"load":{"average":4.35,"cores":14},"batch":{"ms":24098},"invariants":[{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24098,"reason":"1 of 1 tests under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week\" failed: a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week","testMs":399,"mode":"batched","state":"requirement","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]}]} +{"kind":"refutation","at":"2026-10-27T00:15:20.968Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","broke":"made the audit compare nothing, so every sampled kept parse agrees (warmParses in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week\" failed: a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week","commit":"a3bdbc1","dirty":true} +{"at":"2026-10-27T00:15:49.566Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"a3bdbc1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24961,"load":{"average":3.89,"cores":14},"batch":{"ms":24493},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24493,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":273,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24493,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":497,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]}]} +{"at":"2026-10-27T00:16:38.158Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"a3bdbc1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":48293,"load":{"average":3.77,"cores":14},"invariants":[{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24032,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24231,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.cac51ead.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.cac51ead.jsonl new file mode 100644 index 00000000..03591781 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.cac51ead.jsonl @@ -0,0 +1,51 @@ +{"at":"2026-10-27T16:16:13.248Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25541,"load":{"average":7.34,"cores":14},"batch":{"ms":25186},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25186,"reason":"1 of 1 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":410,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T16:16:13.565Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"packed the tarball from the working tree, as npm pack in the repository does (prereleaseCommands in src/lifecycle/prerelease.ts)","verdict":"fail","reason":"1 of 1 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T16:16:41.382Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27219,"load":{"average":6.84,"cores":14},"batch":{"ms":26851},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26851,"reason":"1 of 1 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":1395,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T16:16:41.691Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"fetched the remote by its configured refspec, so a remote set to fetch fewer branches left main stale (prereleaseProblems in src/lifecycle/prerelease.ts)","verdict":"fail","reason":"1 of 1 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T16:21:43.648Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":30432,"load":{"average":36.9,"cores":14},"batch":{"ms":29963},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29963,"reason":"1 of 1 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":3944,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T16:21:43.934Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"matched GitHub by any host ending in its name (repositoryOf in src/lifecycle/prerelease.ts)","verdict":"fail","reason":"1 of 1 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T16:22:17.312Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":32776,"load":{"average":26.31,"cores":14},"batch":{"ms":32410},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32410,"reason":"1 of 1 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":4057,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T16:22:18.196Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"passed over a manifest that does not read (versionsOf in src/lifecycle/prerelease.ts)","verdict":"fail","reason":"1 of 1 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T16:23:03.233Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":43131,"load":{"average":23.53,"cores":14},"batch":{"ms":42071},"invariants":[{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":42071,"reason":"no test ran under the name \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in\" in node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","mode":"batched","state":"structural defect","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config, so the machine key never lands in whatever folder a process starts in"]}]} +{"at":"2026-10-27T16:23:43.179Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24753,"load":{"average":34.98,"cores":14},"batch":{"ms":24418},"invariants":[{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24418,"reason":"1 of 1 tests under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in\" failed: Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in","testMs":3,"mode":"batched","state":"structural defect","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in"]}]} +{"kind":"refutation","at":"2026-10-27T16:23:43.487Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","broke":"took HOME whatever it holds (homeOf in src/lifecycle/user-dir.ts)","verdict":"fail","reason":"1 of 1 tests under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in\" failed: Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in","commit":"887abd8","dirty":true} +{"at":"2026-10-27T16:30:24.709Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":38537,"load":{"average":31.26,"cores":14},"batch":{"ms":37233},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37233,"reason":"6 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":9634,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37233,"reason":"1 test under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37233,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":260,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37233,"reason":"1 test under \"a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":325,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37233,"reason":"1 test under \"a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":477,"mode":"batched","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37233,"reason":"1 test under \"a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":5624,"mode":"batched","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":278,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":578,"symbol":"ParseStore.of.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":590,"symbol":"ParseStore.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":598,"symbol":"ParseStore.constructor","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":843,"symbol":"StoreFolder.constructor","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":848,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":850,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":854,"symbol":"StoreFolder.all","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":856,"symbol":"StoreFolder.all","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":857,"symbol":"StoreFolder.all","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":857,"symbol":"StoreFolder.all.map() callback","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":940,"symbol":"StoreFolder.readWithFirstLine.firstLine","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":954,"symbol":"StoreFolder.firstLine","class":"inside","of":"chokepoint","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":420,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:819 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["StoreFolder in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37233,"reason":"1 test under \"the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":34,"mode":"batched","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":37233,"reason":"1 test under \"a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<8 names> src/**/*.test.ts src/*.e2e.ts","testMs":15,"mode":"batched","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T16:33:55.180Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":210146,"load":{"average":7.32,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29645,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24951,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='Coherence'\\''s folder in the user'\\''s configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/\\.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25195,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path, at \\.coherence, at its parses or at a plugin'\\''s folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25171,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up or speak at a session start: a folder where the store'\\''s file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25394,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a log line is read only where it signs itself with this machine'\\''s key, a torn line is passed over, and a log that fails more than a torn line'\\''s worth is read no further, so a repository'\\''s log costs a few signatures whatever its size' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30288,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log'\\''s path never holds a process up, and a key file too short to be one is replaced' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24779,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees\\.ts outside StoreFolder reads Coherence'\\''s own files or the machine key, and only StoreFolder spells the store'\\''s folder' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24690,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a store'\\''s generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T16:50:09.684Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24949,"load":{"average":5.36,"cores":14},"batch":{"ms":24545},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24545,"reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling","testMs":65,"mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]}]} +{"kind":"refutation","at":"2026-10-27T16:50:09.988Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","broke":"built the TSX parser with @ aliased to string_fragment in a JSX string, as & was (a scratch build of plugins/typescript/tree-sitter-tsx.wasm)","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling","commit":"887abd8","dirty":true} +{"at":"2026-10-27T16:50:36.124Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25544,"load":{"average":5.45,"cores":14},"batch":{"ms":25190},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25190,"reason":"1 of 1 tests under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" failed: the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it","testMs":3,"mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]}]} +{"kind":"refutation","at":"2026-10-27T16:50:36.422Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","broke":"made fetch warn on a digest that differs rather than exit (grammars/tree-sitter-typescript/build.sh)","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" failed: the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it","commit":"887abd8","dirty":true} +{"at":"2026-10-27T16:51:02.332Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25314,"load":{"average":5.56,"cores":14},"batch":{"ms":24970},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24970,"reason":"1 of 1 tests under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" failed: the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it","testMs":2,"mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]}]} +{"kind":"refutation","at":"2026-10-27T16:51:02.647Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","broke":"skipped the CI step that runs build.sh (if: false, .github/workflows/ci.yml)","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" failed: the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it","commit":"887abd8","dirty":true} +{"at":"2026-10-27T16:51:29.034Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25791,"load":{"average":5.7,"cores":14},"batch":{"ms":25439},"invariants":[{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25439,"reason":"1 of 1 tests under \"a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one\" failed: a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one","testMs":107,"mode":"batched","state":"structural defect","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one"]}]} +{"kind":"refutation","at":"2026-10-27T16:51:29.342Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","broke":"kept from a change only what a reading can open, dropping a link to a folder or to nothing (isOtherOnDisk in src/adapters/project-files.ts)","verdict":"fail","reason":"1 of 1 tests under \"a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one\" failed: a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one","commit":"887abd8","dirty":true} +{"at":"2026-10-27T16:52:34.331Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":37980,"load":{"average":4.88,"cores":14},"batch":{"ms":36368},"invariants":[{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":123,"mode":"batched","state":"invariant","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one"]},{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"6 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":8701,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":66,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":252,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":271,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":486,"mode":"batched","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":5647,"mode":"batched","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sitesRef":{"hash":"sha256:ad1c264debb2a29e58c470e707af5c94df1ba451c0b2a5fd399a29273182c345","at":"2026-10-27T16:30:24.709Z"},"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":701,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:819 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["StoreFolder in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":33,"mode":"batched","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36368,"reason":"1 test under \"a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":14,"mode":"batched","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T16:57:18.252Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":283505,"load":{"average":3.73,"cores":14},"invariants":[{"component":"src/adapters","name":"a reading is handed only files it can open","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25084,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one"]},{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29736,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24729,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='Coherence'\\''s folder in the user'\\''s configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/\\.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24836,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24471,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build\\.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI'\\''s verify waits on the job that runs it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24817,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path, at \\.coherence, at its parses or at a plugin'\\''s folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25026,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up or speak at a session start: a folder where the store'\\''s file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said"]},{"component":"src/plugins","name":"a store's log costs a repository nothing and lies to no reading","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25187,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a log line is read only where it signs itself with this machine'\\''s key, a torn line is passed over, and a log that fails more than a torn line'\\''s worth is read no further, so a repository'\\''s log costs a few signatures whatever its size' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a log line is read only where it signs itself with this machine's key, a torn line is passed over, and a log that fails more than a torn line's worth is read no further, so a repository's log costs a few signatures whatever its size"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30341,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log'\\''s path never holds a process up, and a key file too short to be one is replaced' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24592,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees\\.ts outside StoreFolder reads Coherence'\\''s own files or the machine key, and only StoreFolder spells the store'\\''s folder' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store touches its files only through StoreFolder: every use of node:fs in syntax-trees.ts outside StoreFolder reads Coherence's own files or the machine key, and only StoreFolder spells the store's folder"]},{"component":"src/plugins","name":"a store's generation changes only where it is rewritten","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24645,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a store'\\''s generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a store's generation is made only where ParseStore seals the store, for a rewrite or a discard, and an append writes only the log: no write but a rewrite or a discard changes the generation a process loaded"]}]} +{"at":"2026-10-27T17:18:55.626Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24660,"load":{"average":4.04,"cores":14},"batch":{"ms":24315},"invariants":[{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24315,"reason":"1 of 1 tests under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in\" failed: Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in","testMs":3,"mode":"batched","state":"structural defect","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in"]}]} +{"kind":"refutation","at":"2026-10-27T17:18:55.939Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","broke":"asked Node for the home without letting it throw (homeOf in src/lifecycle/user-dir.ts)","verdict":"fail","reason":"1 of 1 tests under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in\" failed: Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:19:27.165Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":30637,"load":{"average":4.45,"cores":14},"batch":{"ms":30292},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30292,"reason":"2 of 6 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has a change no commit holds, a plugin left at another version, a manifest that does not read or names no version, and a commit not pushed are each refused, every version read from HEAD; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":9904,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T17:19:27.477Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"read the versions from the working tree (versionsOf in src/lifecycle/prerelease.ts)","verdict":"fail","reason":"2 of 6 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has a change no commit holds, a plugin left at another version, a manifest that does not read or names no version, and a commit not pushed are each refused, every version read from HEAD; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:20:00.067Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31996,"load":{"average":4.99,"cores":14},"batch":{"ms":31643},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31643,"reason":"2 of 6 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has a branch that holds main, pushed, at one version throughout, is cut, its tarball packed from a clone of HEAD alone; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":12917,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T17:20:00.378Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"left unsaid a file the package's files name that no commit holds (prereleaseProblems in src/lifecycle/prerelease.ts)","verdict":"fail","reason":"2 of 6 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has a branch that holds main, pushed, at one version throughout, is cut, its tarball packed from a clone of HEAD alone; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:20:30.291Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29326,"load":{"average":5,"cores":14},"batch":{"ms":28981},"invariants":[{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28981,"reason":"1 of 1 tests under \"a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" failed: a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced","testMs":3309,"mode":"batched","state":"structural defect","enforces":["a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced"]}]} +{"kind":"refutation","at":"2026-10-27T17:20:30.688Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","broke":"trusted a key file of a key's length whoever may read it (ownKey in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced\" failed: a process that lives long reads again what another process discarded, even when it appended since or the store was its log alone, a pipe the project puts at the log's path never holds a process up, and a key file too short to be one is replaced","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:55:38.584Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26153,"load":{"average":6.38,"cores":14},"batch":{"ms":25823},"invariants":[{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25823,"reason":"1 of 1 tests under \"a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse\" failed: a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse","testMs":209,"mode":"batched","state":"structural defect","enforces":["a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse"]}]} +{"kind":"refutation","at":"2026-10-27T17:55:38.993Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","broke":"wrote no segment, so nothing is kept between processes (StoreFolder.writeSegment in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse\" failed: a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:56:06.806Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27186,"load":{"average":6.71,"cores":14},"batch":{"ms":26822},"invariants":[{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26822,"reason":"1 of 1 tests under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" failed: a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week","testMs":409,"mode":"batched","state":"structural defect","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]}]} +{"kind":"refutation","at":"2026-10-27T17:56:07.187Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","broke":"left the stale store's segments in place (ParseStore.discard in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" failed: a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:56:34.530Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26730,"load":{"average":6.97,"cores":14},"batch":{"ms":26359},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26359,"reason":"1 of 1 tests under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing\" failed: the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing","testMs":201,"mode":"batched","state":"structural defect","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing"]}]} +{"kind":"refutation","at":"2026-10-27T17:56:34.943Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","broke":"used a cache folder whoever owns or may write it (ownFolder in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing\" failed: the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:57:08.372Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":32823,"load":{"average":7.68,"cores":14},"batch":{"ms":32448},"invariants":[{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32448,"reason":"1 of 1 tests under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" failed: a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes","testMs":6581,"mode":"batched","state":"structural defect","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]}]} +{"kind":"refutation","at":"2026-10-27T17:57:08.775Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","broke":"read a source file of any size in the warm-up (warmText in src/economy/warm-parses.ts)","verdict":"fail","reason":"1 of 1 tests under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" failed: a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:58:06.817Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":57458,"load":{"average":6.68,"cores":14},"batch":{"ms":57105},"invariants":[{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":57105,"reason":"1 of 1 tests under \"a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store\" failed: a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store","testMs":58,"mode":"batched","state":"structural defect","enforces":["a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store"]}]} +{"kind":"refutation","at":"2026-10-27T17:58:07.224Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","broke":"kept answering from segments another process removed (ParseStore.readNew in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store\" failed: a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:58:33.678Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25814,"load":{"average":30.12,"cores":14},"batch":{"ms":25439},"invariants":[{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25439,"reason":"1 of 1 tests under \"the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's\" failed: the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's","testMs":1,"mode":"batched","state":"structural defect","enforces":["the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's"]}]} +{"kind":"refutation","at":"2026-10-27T17:58:34.007Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","broke":"exported parsesFolder (src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's\" failed: the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:59:00.713Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26111,"load":{"average":21.97,"cores":14},"batch":{"ms":25751},"invariants":[{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25751,"reason":"1 of 1 tests under \"a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept\" failed: a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept","testMs":65,"mode":"batched","state":"structural defect","enforces":["a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept"]}]} +{"kind":"refutation","at":"2026-10-27T17:59:01.029Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","broke":"warmed a leaf alone, not the registry's top (warmProjectParses in src/economy/warm-parses.ts)","verdict":"fail","reason":"1 of 1 tests under \"a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept\" failed: a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:59:28.664Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27037,"load":{"average":16.12,"cores":14},"batch":{"ms":26690},"invariants":[{"component":"src/plugins","name":"a warm-up keeps the store small and runs once per project","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26690,"reason":"1 of 1 tests under \"a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs\" failed: a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs","testMs":934,"mode":"batched","state":"requirement","enforces":["a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs"]}]} +{"kind":"refutation","at":"2026-10-27T17:59:28.990Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a warm-up keeps the store small and runs once per project","form":"totality oracle","broke":"never merged a store's segments (SEGMENTS_MAX in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs\" failed: a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs","commit":"887abd8","dirty":true} +{"at":"2026-10-27T18:01:28.284Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":38043,"load":{"average":7.19,"cores":14},"batch":{"ms":36515},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":11228,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":2,"mode":"batched","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":421,"mode":"batched","state":"invariant","enforces":["a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":461,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":642,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":268,"mode":"batched","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":324,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":2686,"mode":"batched","state":"invariant","enforces":["a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":262,"symbol":"warmParses","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":285,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":572,"symbol":"ParseStore.of.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":582,"symbol":"ParseStore.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":584,"symbol":"ParseStore.constructor","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":671,"symbol":"ParseStore.discard","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":744,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":745,"symbol":"StoreFolder.of.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":753,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":824,"symbol":"StoreFolder.prune.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":833,"symbol":"StoreFolder.prune.folder","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":841,"symbol":"StoreFolder.writeAudit.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":853,"symbol":"StoreFolder.audits.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":855,"symbol":"StoreFolder.audits.folder","class":"inside","of":"chokepoint","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":645,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:709 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["StoreFolder in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":0,"mode":"batched","state":"invariant","enforces":["the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's"]},{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":124,"mode":"batched","state":"invariant","enforces":["a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept"]},{"component":"src/plugins","name":"a warm-up keeps the store small and runs once per project","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":36515,"reason":"1 test under \"a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<11 names> src/**/*.test.ts src/*.e2e.ts","testMs":919,"mode":"batched","state":"invariant","enforces":["a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs"]}]} +{"at":"2026-10-27T18:06:40.677Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":312075,"load":{"average":9.77,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31364,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26809,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='Coherence'\\''s folder in the user'\\''s configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/\\.config under a home that is absolute, HOME'\\''s, the account'\\''s or Node'\\''s, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25678,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a project'\\''s parses are kept between processes, in the user'\\''s cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26135,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52247,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25516,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store lives outside every project and is used only where the user'\\''s cache is the user'\\''s alone: a project'\\''s own \\.coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24598,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24183,"reason":"passed in the batched invocation, failed in its own: node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 1","mode":"one-at-a-time","state":"structural defect","enforces":["a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24852,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store'\\''s path is made in this module alone, under the user'\\''s cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence'\\''s' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's"]},{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25193,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a registry'\\''s leaves and its top share the user'\\''s one parse store: a warm-up of one leaf pre-reads the leaf and the top'\\''s files, and a warm-up of another reads what the first kept' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept"]},{"component":"src/plugins","name":"a warm-up keeps the store small and runs once per project","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25450,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs"]}]} +{"at":"2026-10-27T18:23:16.905Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":37146,"load":{"average":18.32,"cores":14},"batch":{"ms":35783},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":10721,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":63,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":2,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]},{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":408,"mode":"batched","state":"invariant","enforces":["a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":630,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":265,"mode":"batched","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":323,"mode":"batched","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":2835,"mode":"batched","state":"invariant","enforces":["a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"chokepoint","grade":"visibility-choked","verdict":"pass","enforcer":"the compiler","from":{"value":"anywhere","by":"default"},"refutation":"refused by the language","bypasses":[],"sites":[{"file":"src/plugins/syntax-trees.ts","line":262,"symbol":"warmParses","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":285,"symbol":"staleParsesNotice","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":572,"symbol":"ParseStore.of.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":582,"symbol":"ParseStore.folder","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":584,"symbol":"ParseStore.constructor","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":671,"symbol":"ParseStore.discard","class":"chokepoint-reference","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":744,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":745,"symbol":"StoreFolder.of.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":753,"symbol":"StoreFolder.of","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":824,"symbol":"StoreFolder.prune.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":833,"symbol":"StoreFolder.prune.folder","class":"inside","of":"chokepoint","test":false},{"file":"src/plugins/syntax-trees.ts","line":841,"symbol":"StoreFolder.writeAudit.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":853,"symbol":"StoreFolder.audits.parses","class":"inside","of":"protected","test":false},{"file":"src/plugins/syntax-trees.ts","line":855,"symbol":"StoreFolder.audits.folder","class":"inside","of":"chokepoint","test":false}],"testReferences":0,"files":["src/plugins/syntax-trees.ts"],"latency":481,"reason":"parsesFolder in src/plugins/syntax-trees.ts is visibility-choked, enforced by the compiler: not visible outside its module (src/plugins/syntax-trees.ts:709 declares parsesFolder without export and no export list names it) and every reference inside the chokepoint","state":"invariant","enforces":["StoreFolder in src/plugins/syntax-trees.ts"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":0,"mode":"batched","state":"invariant","enforces":["the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's"]},{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":110,"mode":"batched","state":"invariant","enforces":["a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept"]},{"component":"src/plugins","name":"a warm-up keeps the store small and runs once per project","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":35783,"reason":"1 test under \"a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<12 names> src/**/*.test.ts src/*.e2e.ts","testMs":905,"mode":"batched","state":"invariant","enforces":["a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs"]}]} +{"at":"2026-10-27T18:28:22.687Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"cold"},"latency":305449,"load":{"average":5.48,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29834,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/lifecycle","name":"Coherence's own folder is absolute","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24315,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='Coherence'\\''s folder in the user'\\''s configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/\\.config under a home that is absolute, HOME'\\''s, the account'\\''s or Node'\\''s, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24386,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24235,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers\\.sha256 records, which the build phase checks its build against' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]},{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24656,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a project'\\''s parses are kept between processes, in the user'\\''s cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25190,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24619,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store lives outside every project and is used only where the user'\\''s cache is the user'\\''s alone: a project'\\''s own \\.coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write keeps nothing"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25240,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes"]},{"component":"src/plugins","name":"a long-lived process reads what other processes did","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27430,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a process that lives long reads the segments other processes wrote since, at most once a second, and reads the store again when a segment it read is gone; a process that parses and exits writes what it parsed without reading the store"]},{"component":"src/plugins","name":"the parse store touches its files only through StoreFolder","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24606,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store'\\''s path is made in this module alone, under the user'\\''s cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence'\\''s' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store's path is made in this module alone, under the user's cache: neither parsesFolder nor StoreFolder is exported, parsesFolder builds on userCacheDir, and the module names no project folder of Coherence's"]},{"component":"src/plugins","name":"a registry's leaves share one parse store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25035,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a registry'\\''s leaves and its top share the user'\\''s one parse store: a warm-up of one leaf pre-reads the leaf and the top'\\''s files, and a warm-up of another reads what the first kept' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept"]},{"component":"src/plugins","name":"a warm-up keeps the store small and runs once per project","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25868,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up merges a store of many segments into one, keeping what it read and what any pass wrote in the last fourteen days, and another warm-up of the same project skips while one runs"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.d1efbd7e.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.d1efbd7e.jsonl new file mode 100644 index 00000000..0dad6565 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.d1efbd7e.jsonl @@ -0,0 +1,6 @@ +{"at":"2026-10-26T19:46:44.012Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23490,"load":{"average":4.03,"cores":14},"batch":{"ms":23135},"invariants":[{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23135,"reason":"1 test under \"a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":378,"mode":"batched","state":"requirement","enforces":["a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would"]}]} +{"at":"2026-10-26T19:47:08.087Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23790,"load":{"average":4.78,"cores":14},"invariants":[{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23757,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a project'\\''s parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would"]}]} +{"at":"2026-10-26T19:47:32.636Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23897,"load":{"average":4.78,"cores":14},"batch":{"ms":23594},"invariants":[{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23594,"reason":"1 of 1 tests under \"a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would\" failed: a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would","testMs":200,"mode":"batched","state":"requirement","enforces":["a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would"]}]} +{"kind":"refutation","at":"2026-10-26T19:47:32.926Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","broke":"made the kept parses answer nothing, so every process parses every text (src/plugins/syntax-trees.ts ParseStore.get)","verdict":"fail","reason":"1 of 1 tests under \"a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would\" failed: a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would","commit":"1aef204","dirty":true} +{"at":"2026-10-26T19:47:58.265Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24641,"load":{"average":4.79,"cores":14},"batch":{"ms":24315},"invariants":[{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24315,"reason":"1 test under \"a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":398,"mode":"batched","state":"invariant","enforces":["a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would"]}]} +{"at":"2026-10-26T19:48:22.759Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"1aef204","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24191,"load":{"average":4.94,"cores":14},"invariants":[{"component":"src/plugins","name":"a project's parses are kept between processes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24158,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a project'\\''s parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f0be580a.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f0be580a.jsonl new file mode 100644 index 00000000..aac96d6f --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f0be580a.jsonl @@ -0,0 +1,10 @@ +{"at":"2026-10-26T23:14:11.522Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27798,"load":{"average":5.91,"cores":14},"batch":{"ms":27351},"invariants":[{"component":"src/plugins","name":"the plugin guide's tables list what the code holds","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":27351,"reason":"1 test under \"docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"requirement","enforces":["docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods"]},{"component":"src/plugins","name":"the plugin guide's examples validate","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":27351,"reason":"1 test under \"every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"requirement","enforces":["every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys"]},{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":27351,"reason":"1 test under \"docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"requirement","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} +{"at":"2026-10-26T23:15:31.501Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":79532,"load":{"average":5.75,"cores":14},"invariants":[{"component":"src/plugins","name":"the plugin guide's tables list what the code holds","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26581,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='docs/plugins\\.md'\\''s tables list exactly what the code holds: the duties plugin check runs, the manifest'\\''s keys, the syntax slots, the treeSitter keys, the captures and the adapter'\\''s methods' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods"]},{"component":"src/plugins","name":"the plugin guide's examples validate","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26278,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every plugin\\.json example in docs/plugins\\.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter'\\''s keys' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys"]},{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26631,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='docs/plugins\\.md'\\''s claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} +{"at":"2026-10-26T23:16:15.454Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27526,"load":{"average":9.28,"cores":14},"batch":{"ms":27104},"invariants":[{"component":"src/plugins","name":"the plugin guide's tables list what the code holds","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":27104,"reason":"1 of 1 tests under \"docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods\" failed: docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods","testMs":2,"mode":"batched","state":"requirement","enforces":["docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods"]}]} +{"kind":"refutation","at":"2026-10-26T23:16:15.852Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the plugin guide's tables list what the code holds","form":"totality oracle","broke":"dropped the server agrees row from the guide's duty table (docs/plugins.md)","verdict":"fail","reason":"1 of 1 tests under \"docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods\" failed: docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods","commit":"c30c378","dirty":true} +{"at":"2026-10-26T23:16:41.036Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24514,"load":{"average":7.89,"cores":14},"batch":{"ms":24187},"invariants":[{"component":"src/plugins","name":"the plugin guide's examples validate","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24187,"reason":"1 of 1 tests under \"every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys\" failed: every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys","testMs":1,"mode":"batched","state":"requirement","enforces":["every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys"]}]} +{"kind":"refutation","at":"2026-10-26T23:16:41.344Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the plugin guide's examples validate","form":"totality oracle","broke":"set the guide's manifest example back to pluginApi 2, as the 1.11.0-beta.0 guide had it (docs/plugins.md)","verdict":"fail","reason":"1 of 1 tests under \"every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys\" failed: every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys","commit":"c30c378","dirty":true} +{"at":"2026-10-26T23:17:06.119Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24104,"load":{"average":6.8,"cores":14},"batch":{"ms":23788},"invariants":[{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23788,"reason":"1 of 1 tests under \"docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser\" failed: docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser","testMs":1,"mode":"batched","state":"requirement","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} +{"kind":"refutation","at":"2026-10-26T23:17:06.419Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","broke":"made the guide say to start from go, which reads by hand, as the 1.11.0-beta.0 guide did (docs/plugins.md)","verdict":"fail","reason":"1 of 1 tests under \"docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser\" failed: docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser","commit":"c30c378","dirty":true} +{"at":"2026-10-26T23:17:30.753Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23798,"load":{"average":6.21,"cores":14},"batch":{"ms":23467},"invariants":[{"component":"src/plugins","name":"the plugin guide's tables list what the code holds","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23467,"reason":"1 test under \"docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"invariant","enforces":["docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods"]},{"component":"src/plugins","name":"the plugin guide's examples validate","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23467,"reason":"1 test under \"every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"invariant","enforces":["every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys"]},{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23467,"reason":"1 test under \"docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"invariant","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} +{"at":"2026-10-26T23:18:41.839Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":70791,"load":{"average":7.43,"cores":14},"invariants":[{"component":"src/plugins","name":"the plugin guide's tables list what the code holds","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23741,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='docs/plugins\\.md'\\''s tables list exactly what the code holds: the duties plugin check runs, the manifest'\\''s keys, the syntax slots, the treeSitter keys, the captures and the adapter'\\''s methods' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods"]},{"component":"src/plugins","name":"the plugin guide's examples validate","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23465,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='every plugin\\.json example in docs/plugins\\.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter'\\''s keys' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys"]},{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23551,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='docs/plugins\\.md'\\''s claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f3779918.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f3779918.jsonl new file mode 100644 index 00000000..96e9d5e3 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.f3779918.jsonl @@ -0,0 +1,6 @@ +{"at":"2026-10-26T21:43:39.281Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"6ef2867","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23674,"load":{"average":4.16,"cores":14},"batch":{"ms":23323},"invariants":[{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23323,"reason":"1 test under \"plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":79,"mode":"batched","state":"requirement","enforces":["plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name"]}]} +{"at":"2026-10-26T21:44:02.913Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"6ef2867","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23325,"load":{"average":4.68,"cores":14},"invariants":[{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23292,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name"]}]} +{"at":"2026-10-26T21:44:27.266Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"6ef2867","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23715,"load":{"average":4.68,"cores":14},"batch":{"ms":23391},"invariants":[{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23391,"reason":"1 of 1 tests under \"plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name\" failed: plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name","testMs":44,"mode":"batched","state":"requirement","enforces":["plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name"]}]} +{"kind":"refutation","at":"2026-10-26T21:44:27.561Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","broke":"let a name an import list renames pass whether or not the source scan reads it imported (src/plugins/check.ts answersAgree)","verdict":"fail","reason":"1 of 1 tests under \"plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name\" failed: plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name","commit":"6ef2867","dirty":true} +{"at":"2026-10-26T21:44:51.899Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"6ef2867","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23748,"load":{"average":4.76,"cores":14},"batch":{"ms":23406},"invariants":[{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23406,"reason":"1 test under \"plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":77,"mode":"batched","state":"invariant","enforces":["plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name"]}]} +{"at":"2026-10-26T21:45:15.660Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"6ef2867","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23465,"load":{"average":4.13,"cores":14},"invariants":[{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23434,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name"]}]} diff --git a/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.fb7a6b92.jsonl b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.fb7a6b92.jsonl new file mode 100644 index 00000000..8edd5241 --- /dev/null +++ b/.coherence/runs/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.fb7a6b92.jsonl @@ -0,0 +1,22 @@ +{"at":"2026-10-27T00:45:11.658Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24982,"load":{"average":3.25,"cores":14},"batch":{"ms":24318},"invariants":[{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24318,"reason":"1 test under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":129,"mode":"batched","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24318,"reason":"1 test under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":69,"mode":"batched","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24318,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":440,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24318,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":611,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24318,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":81,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24318,"reason":"1 test under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":4,"mode":"batched","state":"requirement","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]},{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24318,"reason":"1 test under \"docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"invariant","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} +{"at":"2026-10-27T00:47:55.479Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":163523,"load":{"average":3.8,"cores":14},"invariants":[{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23337,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads TypeScript'\\''s imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23209,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23745,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23943,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23454,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22209,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store'\\''s file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]},{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23342,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='docs/plugins\\.md'\\''s claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} +{"at":"2026-10-27T00:48:43.034Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23051,"load":{"average":3.64,"cores":14},"batch":{"ms":22759},"invariants":[{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22759,"reason":"1 of 1 tests under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" failed: the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment","testMs":84,"mode":"batched","state":"structural defect","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]}]} +{"kind":"refutation","at":"2026-10-27T00:48:43.314Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","broke":"dropped the TypeScript plugin's alternate parser, so only the TSX grammar reads (plugins/typescript/plugin.json treeSitter.alternate)","verdict":"fail","reason":"1 of 1 tests under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" failed: the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment","commit":"3a49cd3","dirty":true} +{"at":"2026-10-27T00:49:06.255Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22440,"load":{"average":4.23,"cores":14},"batch":{"ms":22141},"invariants":[{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22141,"reason":"1 of 1 tests under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name\" failed: a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name","testMs":20,"mode":"batched","state":"structural defect","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name"]}]} +{"kind":"refutation","at":"2026-10-27T00:49:06.531Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","broke":"never loaded or compiled the alternate parser, so queries that do not compile against it pass (compile in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name\" failed: a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name","commit":"3a49cd3","dirty":true} +{"at":"2026-10-27T00:49:29.604Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22542,"load":{"average":3.97,"cores":14},"batch":{"ms":22250},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22250,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":93,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]}]} +{"at":"2026-10-27T00:49:52.854Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22433,"load":{"average":4.6,"cores":14},"batch":{"ms":22135},"invariants":[{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":22135,"reason":"1 of 1 tests under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" failed: a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said","testMs":12,"mode":"batched","state":"requirement","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]}]} +{"kind":"refutation","at":"2026-10-27T00:49:53.129Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","broke":"honored a warm-up lock stamped in the future (ParseStore.lock in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" failed: a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said","commit":"3a49cd3","dirty":true} +{"at":"2026-10-27T00:50:16.134Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22428,"load":{"average":4.05,"cores":14},"batch":{"ms":22138},"invariants":[{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22138,"reason":"1 of 1 tests under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" failed: a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said","testMs":15,"mode":"batched","state":"requirement","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]}]} +{"kind":"refutation","at":"2026-10-27T00:50:16.408Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","broke":"let a failed rewrite throw out of the warm-up, as a folder named as the store's file made it (ParseStore.rewrite in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" failed: a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said","commit":"3a49cd3","dirty":true} +{"at":"2026-10-27T00:50:39.298Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22351,"load":{"average":3.79,"cores":14},"batch":{"ms":22057},"invariants":[{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22057,"reason":"1 of 1 tests under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" failed: a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said","testMs":17,"mode":"batched","state":"requirement","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]}]} +{"kind":"refutation","at":"2026-10-27T00:50:39.591Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","broke":"said an audit.json without checking this machine's signature (staleParsesNotice in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" failed: a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said","commit":"3a49cd3","dirty":true} +{"at":"2026-10-27T00:51:03.048Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22895,"load":{"average":4.01,"cores":14},"batch":{"ms":22579},"invariants":[{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22579,"reason":"1 of 1 tests under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week\" failed: a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week","testMs":513,"mode":"batched","state":"structural defect","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]}]} +{"kind":"refutation","at":"2026-10-27T00:51:03.313Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","broke":"said an audit.json without checking this machine's signature (staleParsesNotice in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week\" failed: a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week","commit":"3a49cd3","dirty":true} +{"at":"2026-10-27T00:51:26.230Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22366,"load":{"average":3.36,"cores":14},"batch":{"ms":22072},"invariants":[{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22072,"reason":"1 of 1 tests under \"docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser\" failed: docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser","testMs":2,"mode":"batched","state":"structural defect","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} +{"kind":"refutation","at":"2026-10-27T00:51:26.499Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","broke":"marked go hand-written in the guide's claims, though it reads through a parser (docs/plugins.md)","verdict":"fail","reason":"1 of 1 tests under \"docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser\" failed: docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser","commit":"3a49cd3","dirty":true} +{"at":"2026-10-27T00:51:55.782Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22201,"load":{"average":3.47,"cores":14},"batch":{"ms":21901},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21901,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":91,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]}]} +{"at":"2026-10-27T00:52:43.427Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":22185,"load":{"average":3.16,"cores":14},"batch":{"ms":21897},"invariants":[{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":21897,"reason":"1 of 1 tests under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" failed: the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed","testMs":90,"mode":"batched","state":"structural defect","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]}]} +{"kind":"refutation","at":"2026-10-27T00:52:43.712Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","broke":"signed the store's fingerprint alone, not its contents, as 1.11.0-beta.1 did (ParseStore.sign in src/plugins/syntax-trees.ts)","verdict":"fail","reason":"1 of 1 tests under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" failed: the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed","commit":"3a49cd3","dirty":true} +{"at":"2026-10-27T00:53:35.155Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23526,"load":{"average":2.7,"cores":14},"batch":{"ms":23046},"invariants":[{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23046,"reason":"1 test under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":123,"mode":"batched","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23046,"reason":"1 test under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":67,"mode":"batched","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23046,"reason":"1 test under \"a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":396,"mode":"batched","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23046,"reason":"1 test under \"a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":602,"mode":"batched","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23046,"reason":"1 test under \"the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":79,"mode":"batched","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23046,"reason":"1 test under \"a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]},{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23046,"reason":"1 test under \"docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<7 names> src/**/*.test.ts src/*.e2e.ts","testMs":1,"mode":"batched","state":"invariant","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} +{"at":"2026-10-27T00:56:10.791Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","binding":"none: this session owns no active work order","commit":"3a49cd3","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":155359,"load":{"average":3.61,"cores":14},"invariants":[{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22136,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads TypeScript'\\''s imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22056,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name"]},{"component":"src/plugins","name":"a kept parse is filed under everything it depends on","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22420,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees\\.ts alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone"]},{"component":"src/plugins","name":"a warm-up audits what is kept","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22439,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week"]},{"component":"src/plugins","name":"the parse store never reaches past the project's own folders","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22117,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parse store never reaches past the project'\\''s own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store'\\''s own files are removed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parse store never reaches past the project's own folders: a link on its path keeps no parses and touches nothing, a store or log the project brings is never read or written through, and only the store's own files are removed"]},{"component":"src/plugins","name":"a repository cannot stop a warm-up or speak through the store","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22061,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a repository'\\''s own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store'\\''s file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a repository's own files in the parse store cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future is taken over, and an audit the project brings is never said"]},{"component":"src/plugins","name":"the plugin guide's claims are true of the bundled plugins","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":22095,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='docs/plugins\\.md'\\''s claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser"]}]} diff --git a/.coherence/runs/6a157d1b-4fba-441c-b247-618d60e996ba.d2cf7b16.jsonl b/.coherence/runs/6a157d1b-4fba-441c-b247-618d60e996ba.d2cf7b16.jsonl new file mode 100644 index 00000000..63dd8d2d --- /dev/null +++ b/.coherence/runs/6a157d1b-4fba-441c-b247-618d60e996ba.d2cf7b16.jsonl @@ -0,0 +1,2 @@ +{"at":"2026-10-27T19:11:46.977Z","session":"6a157d1b-4fba-441c-b247-618d60e996ba","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27297,"load":{"average":7.75,"cores":14},"batch":{"ms":26719},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26719,"reason":"1 test under \"a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":26,"mode":"batched","state":"invariant","enforces":["a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through"]},{"component":"src/plugins","name":"an ejected copy is told to eject again","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26719,"reason":"1 test under \"a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":6,"mode":"batched","state":"requirement","enforces":["a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch"]},{"component":"src/plugins","name":"an interfaces table states facts alone","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26719,"reason":"1 test under \"an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":27,"mode":"batched","state":"requirement","enforces":["an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser"]},{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26719,"reason":"1 test under \"plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":117,"mode":"batched","state":"invariant","enforces":["plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name"]}]} +{"at":"2026-10-27T19:13:31.720Z","session":"6a157d1b-4fba-441c-b247-618d60e996ba","agent":"main","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":104291,"load":{"average":9.67,"cores":14},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25915,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a manifest that fills a hand-written reader slot \\(source, declares, topLevel or kept\\) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through"]},{"component":"src/plugins","name":"an ejected copy is told to eject again","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25955,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a copy ejected from Coherence 1\\.10\\.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch"]},{"component":"src/plugins","name":"an interfaces table states facts alone","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26063,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='an interfaces table states its language'\\''s facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser"]},{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26320,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration'\\''s kind from what surrounds it, so its line read alone says otherwise, named by file and name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name"]}]} diff --git a/.coherence/runs/a3f414dba641b7895.a6b398ed.jsonl b/.coherence/runs/a3f414dba641b7895.a6b398ed.jsonl new file mode 100644 index 00000000..211fe57f --- /dev/null +++ b/.coherence/runs/a3f414dba641b7895.a6b398ed.jsonl @@ -0,0 +1,8 @@ +{"at":"2026-10-27T18:11:33.770Z","session":"a3f414dba641b7895","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25059,"load":{"average":5.77,"cores":14},"batch":{"ms":24498},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24498,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":66,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24498,"reason":"1 test under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]}]} +{"at":"2026-10-27T18:12:23.048Z","session":"a3f414dba641b7895","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":48900,"load":{"average":5.17,"cores":14},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24437,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24422,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build\\.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI'\\''s verify waits on the job that runs it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]}]} +{"at":"2026-10-27T18:12:55.877Z","session":"a3f414dba641b7895","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24529,"load":{"average":4.99,"cores":14},"batch":{"ms":24206},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24206,"reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling","testMs":7,"mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]}]} +{"kind":"refutation","at":"2026-10-27T18:12:56.178Z","session":"a3f414dba641b7895","agent":"general-purpose","component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","broke":"put the stock tree-sitter-typescript 0.23.2 parsers, built unpatched with tree-sitter-cli 0.27.1, in place of the bundled ones (plugins/typescript/tree-sitter-typescript.wasm and tree-sitter-tsx.wasm)","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling","commit":"887abd8","dirty":true} +{"at":"2026-10-27T18:13:49.684Z","session":"a3f414dba641b7895","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24590,"load":{"average":5.18,"cores":14},"batch":{"ms":24245},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24245,"reason":"1 of 1 tests under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" failed: the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it","testMs":4,"mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]}]} +{"kind":"refutation","at":"2026-10-27T18:13:50.004Z","session":"a3f414dba641b7895","agent":"general-purpose","component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","broke":"put a TypeScript parser build-phase.sh does not build in place of the bundled one: the patched grammar with & aliased as and in intersection_type alone (plugins/typescript/tree-sitter-typescript.wasm)","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" failed: the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it","commit":"887abd8","dirty":true} +{"at":"2026-10-27T18:14:19.563Z","session":"a3f414dba641b7895","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24922,"load":{"average":4.95,"cores":14},"batch":{"ms":24396},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24396,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":68,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24396,"reason":"1 test under \"the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":2,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]}]} +{"at":"2026-10-27T18:15:08.107Z","session":"a3f414dba641b7895","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":48161,"load":{"average":5.38,"cores":14},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24065,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24064,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build\\.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI'\\''s verify waits on the job that runs it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it"]}]} diff --git a/.coherence/runs/a5eab130eb75915c1.6b50c8c9.jsonl b/.coherence/runs/a5eab130eb75915c1.6b50c8c9.jsonl new file mode 100644 index 00000000..dd126ac9 --- /dev/null +++ b/.coherence/runs/a5eab130eb75915c1.6b50c8c9.jsonl @@ -0,0 +1,8 @@ +{"at":"2026-10-26T23:39:29.865Z","session":"a5eab130eb75915c1","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31465,"load":{"average":33.49,"cores":14},"batch":{"ms":30265},"invariants":[{"component":"src/plugins","name":"a bundled plugin ejects into the project","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30265,"reason":"1 test under \"plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":226,"mode":"batched","state":"invariant","enforces":["plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has"]},{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":30265,"reason":"1 test under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":93,"mode":"batched","state":"requirement","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30265,"reason":"1 test under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":66,"mode":"batched","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]}]} +{"at":"2026-10-26T23:40:41.041Z","session":"a5eab130eb75915c1","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":70884,"load":{"average":14.23,"cores":14},"invariants":[{"component":"src/plugins","name":"a bundled plugin ejects into the project","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23732,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin eject copies a bundled plugin'\\''s source and its check\\.json into the project, its core import named as the package'\\''s, the config pointed at it; and refuses a folder that exists or an entry the config has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has"]},{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23583,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads TypeScript'\\''s imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23536,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]}]} +{"at":"2026-10-26T23:41:10.829Z","session":"a5eab130eb75915c1","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23504,"load":{"average":13.41,"cores":14},"batch":{"ms":23200},"invariants":[{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23200,"reason":"1 of 1 tests under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" failed: the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment","testMs":59,"mode":"batched","state":"requirement","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]}]} +{"kind":"refutation","at":"2026-10-26T23:41:11.130Z","session":"a5eab130eb75915c1","agent":"general-purpose","component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","broke":"read no default import: dropped the pattern that captures import x from \"m\" as @import.default (plugins/typescript/typescript.scm)","verdict":"fail","reason":"1 of 1 tests under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" failed: the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment","commit":"c30c378","dirty":true} +{"at":"2026-10-26T23:41:47.528Z","session":"a5eab130eb75915c1","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23713,"load":{"average":8.74,"cores":14},"batch":{"ms":23409},"invariants":[{"component":"src/plugins","name":"a bundled plugin ejects into the project","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23409,"reason":"1 of 1 tests under \"plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has\" failed: plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has","testMs":204,"mode":"batched","state":"structural defect","enforces":["plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has"]}]} +{"kind":"refutation","at":"2026-10-26T23:41:47.818Z","session":"a5eab130eb75915c1","agent":"general-purpose","component":"src/plugins","name":"a bundled plugin ejects into the project","form":"totality oracle","broke":"read every file of the plugin as text again, its parser's .wasm among them (ejectPlugin in src/plugins/eject.ts)","verdict":"fail","reason":"1 of 1 tests under \"plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has\" failed: plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has","commit":"c30c378","dirty":true} +{"at":"2026-10-26T23:42:42.315Z","session":"a5eab130eb75915c1","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23753,"load":{"average":4.9,"cores":14},"batch":{"ms":23301},"invariants":[{"component":"src/plugins","name":"a bundled plugin ejects into the project","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23301,"reason":"1 test under \"plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":217,"mode":"batched","state":"invariant","enforces":["plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has"]},{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23301,"reason":"1 test under \"the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":88,"mode":"batched","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23301,"reason":"1 test under \"a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":65,"mode":"batched","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]}]} +{"at":"2026-10-26T23:43:52.149Z","session":"a5eab130eb75915c1","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":69544,"load":{"average":5.13,"cores":14},"invariants":[{"component":"src/plugins","name":"a bundled plugin ejects into the project","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23229,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin eject copies a bundled plugin'\\''s source and its check\\.json into the project, its core import named as the package'\\''s, the config pointed at it; and refuses a folder that exists or an entry the config has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has"]},{"component":"src/plugins","name":"a parser reads TypeScript whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23088,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the parser reads TypeScript'\\''s imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment"]},{"component":"src/plugins","name":"a parser is held to what Coherence reads","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23194,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile, and a reading before the runtime starts are each refused by name"]}]} diff --git a/.coherence/runs/a72441caddecdcdf9.e7692dd7.jsonl b/.coherence/runs/a72441caddecdcdf9.e7692dd7.jsonl new file mode 100644 index 00000000..78d010ee --- /dev/null +++ b/.coherence/runs/a72441caddecdcdf9.e7692dd7.jsonl @@ -0,0 +1,18 @@ +{"at":"2026-10-27T17:48:10.262Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31271,"load":{"average":4.39,"cores":14},"batch":{"ms":30731},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30731,"reason":"7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":11226,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"at":"2026-10-27T17:48:41.213Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":30573,"load":{"average":4.19,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30532,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"at":"2026-10-27T17:49:34.595Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31152,"load":{"average":3.2,"cores":14},"batch":{"ms":30743},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30743,"reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":11102,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T17:49:34.986Z","session":"a72441caddecdcdf9","agent":"general-purpose","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"created the release without --prerelease (.github/workflows/prerelease.yml)","verdict":"fail","reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:50:23.891Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31908,"load":{"average":3.48,"cores":14},"batch":{"ms":31569},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31569,"reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":11625,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T17:50:24.205Z","session":"a72441caddecdcdf9","agent":"general-purpose","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"targeted the release at the branch named by the ref input instead of the sha resolved from the checkout (.github/workflows/prerelease.yml)","verdict":"fail","reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:51:21.751Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":32576,"load":{"average":5.64,"cores":14},"batch":{"ms":32154},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32154,"reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":12137,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T17:51:22.074Z","session":"a72441caddecdcdf9","agent":"general-purpose","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"pinned setup-node by its moving tag v7 instead of a commit (.github/workflows/prerelease.yml)","verdict":"fail","reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:52:03.684Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31532,"load":{"average":5.26,"cores":14},"batch":{"ms":31179},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31179,"reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":11718,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T17:52:03.975Z","session":"a72441caddecdcdf9","agent":"general-purpose","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"checked the branch out shallow, dropping fetch-depth: 0, so main's ancestry is not there to read (.github/workflows/prerelease.yml)","verdict":"fail","reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:53:02.012Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31663,"load":{"average":5.41,"cores":14},"batch":{"ms":31298},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31298,"reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":11639,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T17:53:02.389Z","session":"a72441caddecdcdf9","agent":"general-purpose","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"published the tarball to npm from the release step (.github/workflows/prerelease.yml)","verdict":"fail","reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:53:41.492Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":32158,"load":{"average":5.6,"cores":14},"batch":{"ms":31792},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31792,"reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":11956,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T17:53:41.895Z","session":"a72441caddecdcdf9","agent":"general-purpose","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"ran the checks after npm ci and npm pack instead of before them (.github/workflows/prerelease.yml)","verdict":"fail","reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:55:06.659Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":32517,"load":{"average":6.69,"cores":14},"batch":{"ms":32080},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32080,"reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":12140,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T17:55:06.973Z","session":"a72441caddecdcdf9","agent":"general-purpose","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"gave the module back a gh release create after its checks pass (src/lifecycle/prerelease.ts)","verdict":"fail","reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow alone cuts, by hand: it checks a branch out clean with full history, checks it before it installs or packs, makes a prerelease targeting by sha the commit it checked out, with contents: write and nothing more, every action pinned by commit, and never publishes to npm; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:55:44.856Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":32526,"load":{"average":6.38,"cores":14},"batch":{"ms":31990},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31990,"reason":"7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":11674,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"at":"2026-10-27T17:56:18.040Z","session":"a72441caddecdcdf9","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":32797,"load":{"average":7.44,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32757,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} diff --git a/.coherence/runs/a8c20833df2abb361.ef76c476.jsonl b/.coherence/runs/a8c20833df2abb361.ef76c476.jsonl new file mode 100644 index 00000000..6df561bf --- /dev/null +++ b/.coherence/runs/a8c20833df2abb361.ef76c476.jsonl @@ -0,0 +1,14 @@ +{"at":"2026-10-25T02:05:59.477Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25673,"load":{"average":7.08,"cores":16},"batch":{"ms":25387},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25387,"reason":"7 tests under \"entrance detection\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":75,"mode":"batched","state":"invariant","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25387,"reason":"1 test under \"a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":120,"mode":"batched","state":"requirement","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"at":"2026-10-25T02:06:50.132Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":50423,"load":{"average":7.51,"cores":16},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25155,"reason":"passed in the batched invocation, failed in its own: node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='entrance detection' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 but its output did not match /# pass [1-9][0-9]*/; no test ran under that name","mode":"one-at-a-time","state":"structural defect","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25242,"reason":"passed in the batched invocation, failed in its own: node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a list in a Rust file is read by the Rust plugin'\\''s lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 but its output did not match /# pass [1-9][0-9]*/; no test ran under that name","mode":"one-at-a-time","state":"requirement","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"at":"2026-10-25T02:07:19.440Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":311,"load":{"average":10.51,"cores":16},"batch":{"ms":26},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"not run","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts exited 1 and wrote no report at {out}","mode":"batched","state":"invariant","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"not run","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts exited 1 and wrote no report at {out}","mode":"batched","state":"requirement","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"at":"2026-10-25T02:08:10.099Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":50423,"load":{"average":7.43,"cores":16},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25223,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='entrance detection' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25175,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a list in a Rust file is read by the Rust plugin'\\''s lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"at":"2026-10-25T02:08:52.456Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25735,"load":{"average":6.6,"cores":16},"batch":{"ms":25439},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25439,"reason":"7 tests under \"entrance detection\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":78,"mode":"batched","state":"invariant","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25439,"reason":"1 test under \"a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":119,"mode":"batched","state":"requirement","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"at":"2026-10-25T02:09:43.454Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":50767,"load":{"average":6.38,"cores":16},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25303,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='entrance detection' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25437,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a list in a Rust file is read by the Rust plugin'\\''s lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"at":"2026-10-25T02:10:21.869Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25924,"load":{"average":6.56,"cores":16},"batch":{"ms":25627},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25627,"reason":"2 of 7 tests under \"entrance detection\" failed: entrance detection the Rust rules detect what wasm-bindgen and UniFFI export (an exported impl's pub methods and constructor as Type::method, a start fn) and an example's main at Cargo's default paths; never an extern block's imports, a private or plain impl's method, a trait impl wasm-bindgen cannot export, a test module or a tests.rs; entrance detection","testMs":75,"mode":"batched","state":"structural defect","enforces":["entrance detection"]}]} +{"kind":"refutation","at":"2026-10-25T02:10:22.114Z","session":"a8c20833df2abb361","agent":"general-purpose","component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","broke":"read a #[wasm_bindgen] impl as exporting none of its methods, in foreignExports (plugins/rust/rust-entrances.ts)","verdict":"fail","reason":"2 of 7 tests under \"entrance detection\" failed: entrance detection the Rust rules detect what wasm-bindgen and UniFFI export (an exported impl's pub methods and constructor as Type::method, a start fn) and an example's main at Cargo's default paths; never an extern block's imports, a private or plain impl's method, a trait impl wasm-bindgen cannot export, a test module or a tests.rs; entrance detection","commit":"b91e4ad","dirty":true} +{"at":"2026-10-25T02:10:56.453Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25584,"load":{"average":8.17,"cores":16},"batch":{"ms":25317},"invariants":[{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25317,"reason":"1 of 1 tests under \"a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone\" failed: a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone","testMs":86,"mode":"batched","state":"requirement","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"kind":"refutation","at":"2026-10-25T02:10:56.693Z","session":"a8c20833df2abb361","agent":"general-purpose","component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","broke":"read every mirror's list with the TypeScript reader, never the list's language's lists slot, in readLiteral (src/lifecycle/mirrors.ts)","verdict":"fail","reason":"1 of 1 tests under \"a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone\" failed: a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone","commit":"b91e4ad","dirty":true} +{"at":"2026-10-25T02:11:39.703Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25699,"load":{"average":8.22,"cores":16},"batch":{"ms":25408},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25408,"reason":"7 tests under \"entrance detection\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":74,"mode":"batched","state":"invariant","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25408,"reason":"1 test under \"a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":120,"mode":"batched","state":"invariant","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"at":"2026-10-25T02:12:30.378Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":50441,"load":{"average":10.73,"cores":16},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25151,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='entrance detection' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25260,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a list in a Rust file is read by the Rust plugin'\\''s lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"at":"2026-10-25T02:16:21.633Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25797,"load":{"average":21.1,"cores":16},"batch":{"ms":25496},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25496,"reason":"7 tests under \"entrance detection\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":72,"mode":"batched","state":"invariant","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25496,"reason":"1 test under \"a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":120,"mode":"batched","state":"invariant","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} +{"at":"2026-10-25T02:17:12.469Z","session":"a8c20833df2abb361","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"b91e4ad","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":50605,"load":{"average":12.21,"cores":16},"invariants":[{"component":"src/adapters","name":"entrance detection follows listed rules","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25293,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='entrance detection' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["entrance detection"]},{"component":"src/lifecycle","name":"a mirror's list is read in its own language","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25284,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a list in a Rust file is read by the Rust plugin'\\''s lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone"]}]} diff --git a/.coherence/runs/a8c6256d564d40a3c.e09e8193.jsonl b/.coherence/runs/a8c6256d564d40a3c.e09e8193.jsonl new file mode 100644 index 00000000..0a5f4156 --- /dev/null +++ b/.coherence/runs/a8c6256d564d40a3c.e09e8193.jsonl @@ -0,0 +1,12 @@ +{"at":"2026-10-27T19:24:15.794Z","session":"a8c6256d564d40a3c","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":32151,"load":{"average":15.69,"cores":14},"batch":{"ms":31604},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31604,"reason":"7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":12179,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31604,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":65,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31604,"reason":"1 test under \"the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":2,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]}]} +{"at":"2026-10-27T19:25:35.977Z","session":"a8c6256d564d40a3c","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":79774,"load":{"average":9.59,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30450,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24687,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24600,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers\\.sha256 records, which the build phase checks its build against' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]}]} +{"at":"2026-10-27T19:26:08.110Z","session":"a8c6256d564d40a3c","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24576,"load":{"average":8.98,"cores":14},"batch":{"ms":24212},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24212,"reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one","testMs":63,"mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]}]} +{"kind":"refutation","at":"2026-10-27T19:26:08.398Z","session":"a8c6256d564d40a3c","agent":"general-purpose","component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","broke":"built the parsers with a semicolon scanner that does not take = after a member named in (common/scanner.h, the blind reviewer's second break) and put them in place of plugins/typescript/*.wasm","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one\" failed: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:26:44.914Z","session":"a8c6256d564d40a3c","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24635,"load":{"average":7.31,"cores":14},"batch":{"ms":24313},"invariants":[{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24313,"reason":"1 of 1 tests under \"the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against\" failed: the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against","testMs":3,"mode":"batched","state":"structural defect","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]}]} +{"kind":"refutation","at":"2026-10-27T19:26:45.236Z","session":"a8c6256d564d40a3c","agent":"general-purpose","component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","broke":"put parsers built with a semicolon scanner that does not take = after a member named in (common/scanner.h, the blind reviewer's second break) in place of plugins/typescript/*.wasm","verdict":"fail","reason":"1 of 1 tests under \"the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against\" failed: the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:27:36.693Z","session":"a8c6256d564d40a3c","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":30824,"load":{"average":9.84,"cores":14},"batch":{"ms":30455},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30455,"reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has a version that is no prerelease, a tag that exists and tags that cannot be listed are refused, GitHub is matched by its own host alone, and the script spells no remote; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":12436,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T19:27:37.006Z","session":"a8c6256d564d40a3c","agent":"general-purpose","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"read a failed git ls-remote of the remote's tags as no such tag, as before (prereleaseProblems in src/lifecycle/prerelease.ts)","verdict":"fail","reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has a version that is no prerelease, a tag that exists and tags that cannot be listed are refused, GitHub is matched by its own host alone, and the script spells no remote; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:28:20.615Z","session":"a8c6256d564d40a3c","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":34459,"load":{"average":10.96,"cores":14},"batch":{"ms":34096},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":34096,"reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow's shape is linted, not its behaviour: dispatched by hand alone, read access but for the one job that releases, which alone may write contents and checks nothing out, no id-token or environment, every action pinned by commit; the module cuts nothing; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","testMs":13436,"mode":"batched","state":"structural defect","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]}]} +{"kind":"refutation","at":"2026-10-27T19:28:21.013Z","session":"a8c6256d564d40a3c","agent":"general-purpose","component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","broke":"gave the build job, which checks out and runs the branch's code, contents: write (.github/workflows/prerelease.yml)","verdict":"fail","reason":"2 of 7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" failed: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has the workflow's shape is linted, not its behaviour: dispatched by hand alone, read access but for the one job that releases, which alone may write contents and checks nothing out, no id-token or environment, every action pinned by commit; the module cuts nothing; a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:28:56.827Z","session":"a8c6256d564d40a3c","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":30915,"load":{"average":28.17,"cores":14},"batch":{"ms":30410},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30410,"reason":"7 tests under \"a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":11787,"mode":"batched","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30410,"reason":"1 test under \"the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":64,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30410,"reason":"1 test under \"the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<3 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]}]} +{"at":"2026-10-27T19:30:15.500Z","session":"a8c6256d564d40a3c","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":78347,"load":{"average":11.63,"cores":14},"invariants":[{"component":"src/lifecycle","name":"a prerelease carries main","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":29960,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a prerelease is cut only from a clean HEAD on a branch of the remote package\\.json names, holding that remote'\\''s main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has"]},{"component":"src/plugins","name":"the TypeScript parsers read what their release cannot","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24362,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers read what tree-sitter-typescript 0\\.23\\.2 cannot: an import type with type arguments or as an array'\\''s element, an indexed type'\\''s object or keyof'\\''s operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one"]},{"component":"src/plugins","name":"the TypeScript parsers are the ones their build makes","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23995,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers\\.sha256 records, which the build phase checks its build against' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against"]}]} diff --git a/.coherence/runs/a9989dca94e0c7e7a.636da992.jsonl b/.coherence/runs/a9989dca94e0c7e7a.636da992.jsonl new file mode 100644 index 00000000..9eb9ebe6 --- /dev/null +++ b/.coherence/runs/a9989dca94e0c7e7a.636da992.jsonl @@ -0,0 +1,28 @@ +{"at":"2026-10-27T21:32:45.214Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31497,"load":{"average":23.18,"cores":14},"batch":{"ms":31077},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31077,"reason":"1 test under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":445,"mode":"batched","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31077,"reason":"1 test under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":1356,"mode":"batched","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/lifecycle","name":"no totals are injected","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31077,"reason":"1 test under \"no hook injection carries a total: orient names the ranked terms or says nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":702,"mode":"batched","state":"invariant","enforces":["no hook injection carries a total: orient names the ranked terms or says nothing"]},{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31077,"reason":"1 test under \"a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":22,"mode":"batched","state":"invariant","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31077,"reason":"1 test under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":2265,"mode":"batched","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31077,"reason":"1 test under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":1110,"mode":"batched","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"at":"2026-10-27T21:35:23.677Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":158139,"load":{"average":9.58,"cores":14},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25914,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26765,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/lifecycle","name":"no totals are injected","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25824,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='no hook injection carries a total: orient names the ranked terms or says nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["no hook injection carries a total: orient names the ranked terms or says nothing"]},{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25471,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27769,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human'\\''s acknowledgement answers it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26360,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"at":"2026-10-27T21:36:16.119Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25733,"load":{"average":9.61,"cores":14},"batch":{"ms":25391},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25391,"reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","testMs":143,"mode":"batched","state":"structural defect","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]}]} +{"kind":"refutation","at":"2026-10-27T21:36:16.514Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/journal","name":"a defect names its component","form":"totality oracle","broke":"let the defect verb write a defect with no --file, --component or --unplaced, as before (verbs.ts defectPlace)","verdict":"fail","reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:36:53.634Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26123,"load":{"average":9.96,"cores":14},"batch":{"ms":25737},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25737,"reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","testMs":235,"mode":"batched","state":"structural defect","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]}]} +{"kind":"refutation","at":"2026-10-27T21:36:53.950Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/journal","name":"a defect names its component","form":"totality oracle","broke":"decided a --file's owner on the path as written, its .. segments unresolved (verbs.ts defectComponent)","verdict":"fail","reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:37:29.403Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26199,"load":{"average":10.02,"cores":14},"batch":{"ms":25824},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25824,"reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","testMs":487,"mode":"batched","state":"structural defect","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]}]} +{"kind":"refutation","at":"2026-10-27T21:37:29.722Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/journal","name":"a defect names its component","form":"totality oracle","broke":"placed a defect whose files name a component in its guard's component too, the union placeDefect had (dead-ends.ts placeDefect)","verdict":"fail","reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:38:04.449Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27276,"load":{"average":11.5,"cores":14},"batch":{"ms":26898},"invariants":[{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26898,"reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","testMs":1410,"mode":"batched","state":"structural defect","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]}]} +{"kind":"refutation","at":"2026-10-27T21:38:04.843Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","broke":"read each other worktree at its top, not at the project's own folder in it (store.ts worktreesOf out.push(path))","verdict":"fail","reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:38:33.701Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26705,"load":{"average":15.24,"cores":14},"batch":{"ms":26353},"invariants":[{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26353,"reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","testMs":647,"mode":"batched","state":"structural defect","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]}]} +{"kind":"refutation","at":"2026-10-27T21:38:34.160Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","broke":"resolved an answering or cited id in this checkout's journal alone, as before (verbs.ts answerable)","verdict":"fail","reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:39:09.912Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26886,"load":{"average":15.33,"cores":14},"batch":{"ms":26540},"invariants":[{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26540,"reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","testMs":1007,"mode":"batched","state":"structural defect","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]}]} +{"kind":"refutation","at":"2026-10-27T21:39:10.313Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","broke":"read the checkout's own journal through loadJournal first, which throws on a store file it cannot read, as before (store.ts loadJournalAcrossWorktrees)","verdict":"fail","reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:39:38.555Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26455,"load":{"average":11.02,"cores":14},"batch":{"ms":26115},"invariants":[{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26115,"reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","testMs":533,"mode":"batched","state":"structural defect","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]}]} +{"kind":"refutation","at":"2026-10-27T21:39:38.949Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","broke":"took a kept file from the index whatever its identity now is (worktree-index.ts known)","verdict":"fail","reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:40:16.809Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27170,"load":{"average":9.14,"cores":14},"batch":{"ms":26826},"invariants":[{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26826,"reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","testMs":1293,"mode":"batched","state":"structural defect","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]}]} +{"kind":"refutation","at":"2026-10-27T21:40:17.207Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","broke":"kept a retracted defect in defectStates, so it still counted toward a dead end (defects.ts defectStates)","verdict":"fail","reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:40:47.650Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28409,"load":{"average":7.28,"cores":14},"batch":{"ms":28068},"invariants":[{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28068,"reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","testMs":2395,"mode":"batched","state":"structural defect","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]}]} +{"kind":"refutation","at":"2026-10-27T21:40:48.054Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","broke":"put back orient's line of what the reading read when no subsystem is at a dead end (dead-ends.ts deadEndBlock)","verdict":"fail","reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:41:25.065Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26845,"load":{"average":6.48,"cores":14},"batch":{"ms":26504},"invariants":[{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26504,"reason":"1 of 1 tests under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" failed: converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed","testMs":1147,"mode":"batched","state":"structural defect","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"kind":"refutation","at":"2026-10-27T21:41:25.465Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/spec","name":"converging work is no dead end","form":"totality oracle","broke":"put back orient's line of what the reading read when no subsystem is at a dead end (dead-ends.ts deadEndBlock)","verdict":"fail","reason":"1 of 1 tests under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" failed: converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:41:52.886Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25519,"load":{"average":6.57,"cores":14},"batch":{"ms":25179},"invariants":[{"component":"src/lifecycle","name":"no totals are injected","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25179,"reason":"1 of 1 tests under \"no hook injection carries a total: orient names the ranked terms or says nothing\" failed: no hook injection carries a total: orient names the ranked terms or says nothing","testMs":127,"mode":"batched","state":"structural defect","enforces":["no hook injection carries a total: orient names the ranked terms or says nothing"]}]} +{"kind":"refutation","at":"2026-10-27T21:41:53.289Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/lifecycle","name":"no totals are injected","form":"totality oracle","broke":"put back orient's dead-end totals line when no subsystem is at a dead end (dead-ends.ts deadEndBlock)","verdict":"fail","reason":"1 of 1 tests under \"no hook injection carries a total: orient names the ranked terms or says nothing\" failed: no hook injection carries a total: orient names the ranked terms or says nothing","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:42:19.681Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25464,"load":{"average":6.26,"cores":14},"batch":{"ms":25012},"invariants":[{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25012,"reason":"1 of 1 tests under \"a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3\" failed: a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3","testMs":24,"mode":"batched","state":"structural defect","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]}]} +{"kind":"refutation","at":"2026-10-27T21:42:20.086Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","broke":"quoted pluginApi 3's parser-path change for every duty again, in place of what each asks (check.ts notHeld)","verdict":"fail","reason":"1 of 1 tests under \"a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3\" failed: a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3","commit":"766fba1","dirty":true} +{"at":"2026-10-27T21:42:57.601Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31471,"load":{"average":6.77,"cores":14},"batch":{"ms":31030},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31030,"reason":"1 test under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":448,"mode":"batched","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31030,"reason":"1 test under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":1323,"mode":"batched","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/lifecycle","name":"no totals are injected","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31030,"reason":"1 test under \"no hook injection carries a total: orient names the ranked terms or says nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":700,"mode":"batched","state":"invariant","enforces":["no hook injection carries a total: orient names the ranked terms or says nothing"]},{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31030,"reason":"1 test under \"a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":21,"mode":"batched","state":"invariant","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31030,"reason":"1 test under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":2280,"mode":"batched","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":31030,"reason":"1 test under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<6 names> src/**/*.test.ts src/*.e2e.ts","testMs":1101,"mode":"batched","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"at":"2026-10-27T21:45:33.332Z","session":"a9989dca94e0c7e7a","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"766fba1","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":155408,"load":{"average":6.42,"cores":14},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24893,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25884,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/lifecycle","name":"no totals are injected","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25928,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='no hook injection carries a total: orient names the ranked terms or says nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["no hook injection carries a total: orient names the ranked terms or says nothing"]},{"component":"src/plugins","name":"a plugin is never failed by a duty newer than its interface","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25204,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27212,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human'\\''s acknowledgement answers it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26249,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} diff --git a/.coherence/runs/aa78b6ceaeb4845e0.13558d9b.jsonl b/.coherence/runs/aa78b6ceaeb4845e0.13558d9b.jsonl new file mode 100644 index 00000000..61829b69 --- /dev/null +++ b/.coherence/runs/aa78b6ceaeb4845e0.13558d9b.jsonl @@ -0,0 +1,12 @@ +{"at":"2026-10-27T17:50:17.029Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28656,"load":{"average":3.35,"cores":14},"batch":{"ms":28118},"invariants":[{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28118,"reason":"1 test under \"spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":1703,"mode":"batched","state":"requirement","enforces":["spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":28118,"reason":"1 test under \"converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":961,"mode":"batched","state":"requirement","enforces":["converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named"]}]} +{"at":"2026-10-27T17:51:11.448Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":54031,"load":{"average":5.45,"cores":14},"invariants":[{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":27090,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human'\\''s acknowledgement answers it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26897,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named"]}]} +{"at":"2026-10-27T17:58:51.034Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27279,"load":{"average":24.79,"cores":14},"batch":{"ms":26901},"invariants":[{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26901,"reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it","testMs":1070,"mode":"batched","state":"requirement","enforces":["spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it"]}]} +{"kind":"refutation","at":"2026-10-27T17:58:51.345Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","broke":"made deadEnds take a subsystem's latest witnessed guard close as its first guard (r.at > first.at), so its count starts after the last guard instead of the first","verdict":"fail","reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it","commit":"887abd8","dirty":true} +{"at":"2026-10-27T17:59:35.815Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27335,"load":{"average":15.15,"cores":14},"batch":{"ms":26952},"invariants":[{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26952,"reason":"1 of 1 tests under \"converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named\" failed: converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named","testMs":1119,"mode":"batched","state":"requirement","enforces":["converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named"]}]} +{"kind":"refutation","at":"2026-10-27T17:59:36.141Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","component":"src/spec","name":"converging work is no dead end","form":"totality oracle","broke":"dropped the returns threshold from deadEnds, so a component crossing the defect, class and round thresholds is a dead end whether or not its defects came back through a guard it already had","verdict":"fail","reason":"1 of 1 tests under \"converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named\" failed: converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named","commit":"887abd8","dirty":true} +{"at":"2026-10-27T18:00:09.959Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25204,"load":{"average":11.41,"cores":14},"batch":{"ms":24847},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24847,"reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","testMs":161,"mode":"batched","state":"requirement","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]}]} +{"kind":"refutation","at":"2026-10-27T18:00:10.255Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","component":"src/journal","name":"a defect names its component","form":"totality oracle","broke":"made the defect verb accept a --component naming no component folder (the refusal's condition can never hold), so the record carries a folder no spec holds","verdict":"fail","reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","commit":"887abd8","dirty":true} +{"at":"2026-10-27T18:00:44.832Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25273,"load":{"average":9.16,"cores":14},"batch":{"ms":24912},"invariants":[{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24912,"reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","testMs":263,"mode":"batched","state":"requirement","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]}]} +{"kind":"refutation","at":"2026-10-27T18:00:45.140Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","broke":"made loadJournalAcrossWorktrees read no worktree but its own (the loop over otherWorktrees sliced to none), as a single-checkout reading does","verdict":"fail","reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","commit":"887abd8","dirty":true} +{"at":"2026-10-27T18:01:25.789Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":29335,"load":{"average":6.54,"cores":14},"batch":{"ms":28806},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28806,"reason":"1 test under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":183,"mode":"batched","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28806,"reason":"1 test under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":385,"mode":"batched","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28806,"reason":"1 test under \"spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":1925,"mode":"batched","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28806,"reason":"1 test under \"converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":1049,"mode":"batched","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named"]}]} +{"at":"2026-10-27T18:03:13.344Z","session":"aa78b6ceaeb4845e0","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"887abd8","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":107208,"load":{"average":7.5,"cores":14},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25417,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26489,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28651,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human'\\''s acknowledgement answers it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep coming back through its guards across classes, families and rounds, and a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26604,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds that each bought a guard of their own are not named"]}]} diff --git a/.coherence/runs/ad8520a8703d71a7b.049d02d2.jsonl b/.coherence/runs/ad8520a8703d71a7b.049d02d2.jsonl new file mode 100644 index 00000000..bc40660d --- /dev/null +++ b/.coherence/runs/ad8520a8703d71a7b.049d02d2.jsonl @@ -0,0 +1,8 @@ +{"at":"2026-10-26T23:29:37.430Z","session":"ad8520a8703d71a7b","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24361,"load":{"average":8.28,"cores":14},"batch":{"ms":24019},"invariants":[{"component":"src/plugins","name":"a qualified use narrows a whole-module import","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24019,"reason":"1 test under \"a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":24,"mode":"batched","state":"requirement","enforces":["a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole"]},{"component":"src/plugins","name":"Go is read through its parser","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24019,"reason":"1 test under \"a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":14,"mode":"batched","state":"requirement","enforces":["a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing"]}]} +{"at":"2026-10-26T23:30:25.017Z","session":"ad8520a8703d71a7b","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":47283,"load":{"average":7.29,"cores":14},"invariants":[{"component":"src/plugins","name":"a qualified use narrows a whole-module import","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23807,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a whole module the text uses names of through the name its import binds brings in those names, each joined to the module'\\''s file that declares it; one it uses no name of that way stays whole' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole"]},{"component":"src/plugins","name":"Go is read through its parser","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23442,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string \\(a package clause in one among it\\) declare nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing"]}]} +{"at":"2026-10-26T23:30:55.953Z","session":"ad8520a8703d71a7b","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24078,"load":{"average":7.11,"cores":14},"batch":{"ms":23757},"invariants":[{"component":"src/plugins","name":"a qualified use narrows a whole-module import","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23757,"reason":"1 of 1 tests under \"a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole\" failed: a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole","testMs":19,"mode":"batched","state":"requirement","enforces":["a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole"]}]} +{"kind":"refutation","at":"2026-10-26T23:30:56.242Z","session":"ad8520a8703d71a7b","agent":"general-purpose","component":"src/plugins","name":"a qualified use narrows a whole-module import","form":"totality oracle","broke":"had the source slot hand every whole-module import whole, its qualified uses never read (src/plugins/languages.ts treeSlot)","verdict":"fail","reason":"1 of 1 tests under \"a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole\" failed: a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole","commit":"c30c378","dirty":true} +{"at":"2026-10-26T23:31:34.000Z","session":"ad8520a8703d71a7b","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24289,"load":{"average":6.22,"cores":14},"batch":{"ms":23965},"invariants":[{"component":"src/plugins","name":"Go is read through its parser","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23965,"reason":"1 of 1 tests under \"a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing\" failed: a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing","testMs":15,"mode":"batched","state":"requirement","enforces":["a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing"]}]} +{"kind":"refutation","at":"2026-10-26T23:31:34.304Z","session":"ad8520a8703d71a7b","agent":"general-purpose","component":"src/plugins","name":"Go is read through its parser","form":"totality oracle","broke":"had Go's privateName read a name private unless its first letter is an ASCII upper-case one (plugins/go/plugin.json treeSitter.privateName)","verdict":"fail","reason":"1 of 1 tests under \"a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing\" failed: a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing","commit":"c30c378","dirty":true} +{"at":"2026-10-26T23:32:02.928Z","session":"ad8520a8703d71a7b","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24204,"load":{"average":5.68,"cores":14},"batch":{"ms":23864},"invariants":[{"component":"src/plugins","name":"a qualified use narrows a whole-module import","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23864,"reason":"1 test under \"a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":25,"mode":"batched","state":"invariant","enforces":["a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole"]},{"component":"src/plugins","name":"Go is read through its parser","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23864,"reason":"1 test under \"a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<2 names> src/**/*.test.ts src/*.e2e.ts","testMs":14,"mode":"batched","state":"invariant","enforces":["a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing"]}]} +{"at":"2026-10-26T23:32:50.904Z","session":"ad8520a8703d71a7b","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"c30c378","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":47671,"load":{"average":7.05,"cores":14},"invariants":[{"component":"src/plugins","name":"a qualified use narrows a whole-module import","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23875,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a whole module the text uses names of through the name its import binds brings in those names, each joined to the module'\\''s file that declares it; one it uses no name of that way stays whole' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole"]},{"component":"src/plugins","name":"Go is read through its parser","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23763,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string \\(a package clause in one among it\\) declare nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing"]}]} diff --git a/.coherence/runs/ae41053f3d446b86f.cbacda01.jsonl b/.coherence/runs/ae41053f3d446b86f.cbacda01.jsonl new file mode 100644 index 00000000..efed8a6e --- /dev/null +++ b/.coherence/runs/ae41053f3d446b86f.cbacda01.jsonl @@ -0,0 +1,6 @@ +{"at":"2026-10-26T23:36:21.040Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":40633,"load":{"average":40.68,"cores":14},"batch":{"ms":39391},"invariants":[{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":39391,"reason":"1 test under \"a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":22,"mode":"batched","state":"invariant","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused"]}]} +{"at":"2026-10-26T23:36:45.486Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24132,"load":{"average":40.42,"cores":14},"invariants":[{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24096,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused"]}]} +{"at":"2026-10-26T23:37:27.657Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":41450,"load":{"average":40.42,"cores":14},"batch":{"ms":41095},"invariants":[{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":41095,"reason":"1 of 1 tests under \"a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused\" failed: a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused","testMs":22,"mode":"batched","state":"structural defect","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused"]}]} +{"kind":"refutation","at":"2026-10-26T23:37:28.342Z","session":"ae41053f3d446b86f","agent":"general-purpose","component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","broke":"made the census read an import's statement only from its own match, never from a match of its own that holds it (src/plugins/syntax-trees.ts census)","verdict":"fail","reason":"1 of 1 tests under \"a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused\" failed: a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused","commit":"f76b1e0","dirty":true} +{"at":"2026-10-26T23:37:55.628Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25974,"load":{"average":69.75,"cores":14},"batch":{"ms":25275},"invariants":[{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25275,"reason":"1 test under \"a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<1 names> src/**/*.test.ts src/*.e2e.ts","testMs":18,"mode":"batched","state":"invariant","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused"]}]} +{"at":"2026-10-26T23:38:19.864Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23925,"load":{"average":35.23,"cores":14},"invariants":[{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23892,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused"]}]} diff --git a/.coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl b/.coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl new file mode 100644 index 00000000..aae17dca --- /dev/null +++ b/.coherence/runs/ae41053f3d446b86f.d5df4d0b.jsonl @@ -0,0 +1,12 @@ +{"at":"2026-10-26T23:26:45.173Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":33416,"load":{"average":25.59,"cores":14},"batch":{"ms":32274},"invariants":[{"component":"src/adapters","name":"a Rust file declares its top-level items","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32274,"reason":"1 test under \"a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":88,"mode":"batched","state":"requirement","enforces":["a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing"]},{"component":"src/adapters","name":"a Rust use is read in code alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":32274,"reason":"1 test under \"a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read"]},{"component":"src/adapters","name":"a Rust use in an inline module is read from that module","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32274,"reason":"1 test under \"a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":5,"mode":"batched","state":"requirement","enforces":["a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate"]},{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":32274,"reason":"1 test under \"a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":14,"mode":"batched","state":"requirement","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused"]}]} +{"at":"2026-10-26T23:28:22.645Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":97163,"load":{"average":15.2,"cores":14},"invariants":[{"component":"src/adapters","name":"a Rust file declares its top-level items","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24211,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing"]},{"component":"src/adapters","name":"a Rust use is read in code alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24542,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read"]},{"component":"src/adapters","name":"a Rust use in an inline module is read from that module","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24496,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a use inside an inline module is read from that module: super leaves it before the file'\\''s own, a path still inside it leads to no other file, and a bare path there names a crate' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate"]},{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23879,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused"]}]} +{"at":"2026-10-26T23:28:53.566Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23901,"load":{"average":13.16,"cores":14},"batch":{"ms":23586},"invariants":[{"component":"src/adapters","name":"a Rust file declares its top-level items","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23586,"reason":"1 of 1 tests under \"a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing\" failed: a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing","testMs":19,"mode":"batched","state":"requirement","enforces":["a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing"]}]} +{"kind":"refutation","at":"2026-10-26T23:28:53.859Z","session":"ae41053f3d446b86f","agent":"general-purpose","component":"src/adapters","name":"a Rust file declares its top-level items","form":"totality oracle","broke":"dropped the @exported capture from rust.scm's fn pattern, so a pub fn reads as private (plugins/rust/rust.scm)","verdict":"fail","reason":"1 of 1 tests under \"a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing\" failed: a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing","commit":"f76b1e0","dirty":true} +{"at":"2026-10-26T23:29:30.806Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24256,"load":{"average":8.83,"cores":14},"batch":{"ms":23941},"invariants":[{"component":"src/adapters","name":"a Rust use is read in code alone","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23941,"reason":"1 of 1 tests under \"a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read\" failed: a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read","testMs":19,"mode":"batched","state":"structural defect","enforces":["a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read"]}]} +{"kind":"refutation","at":"2026-10-26T23:29:31.117Z","session":"ae41053f3d446b86f","agent":"general-purpose","component":"src/adapters","name":"a Rust use is read in code alone","form":"totality oracle","broke":"dropped rust.scm's prefix pattern for a group's path, so a leaf in a nested group is read without the paths over it (plugins/rust/rust.scm)","verdict":"fail","reason":"1 of 1 tests under \"a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read\" failed: a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read","commit":"f76b1e0","dirty":true} +{"at":"2026-10-26T23:30:02.781Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24167,"load":{"average":7.94,"cores":14},"batch":{"ms":23838},"invariants":[{"component":"src/adapters","name":"a Rust use in an inline module is read from that module","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23838,"reason":"1 of 1 tests under \"a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate\" failed: a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate","testMs":21,"mode":"batched","state":"requirement","enforces":["a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate"]}]} +{"kind":"refutation","at":"2026-10-26T23:30:03.069Z","session":"ae41053f3d446b86f","agent":"general-purpose","component":"src/adapters","name":"a Rust use in an inline module is read from that module","form":"totality oracle","broke":"dropped rust.scm's inline mod prefix, so a use in a test module is read as though written at the file's top (plugins/rust/rust.scm)","verdict":"fail","reason":"1 of 1 tests under \"a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate\" failed: a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate","commit":"f76b1e0","dirty":true} +{"at":"2026-10-26T23:30:36.214Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":23891,"load":{"average":7.75,"cores":14},"batch":{"ms":23563},"invariants":[{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":23563,"reason":"1 of 1 tests under \"a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused\" failed: a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused","testMs":11,"mode":"batched","state":"requirement","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused"]}]} +{"kind":"refutation","at":"2026-10-26T23:30:36.526Z","session":"ae41053f3d446b86f","agent":"general-purpose","component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","broke":"made the speller read an import's own node text alone, its prefixes dropped (src/plugins/syntax-trees.ts speller)","verdict":"fail","reason":"1 of 1 tests under \"a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused\" failed: a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused","commit":"f76b1e0","dirty":true} +{"at":"2026-10-26T23:31:04.508Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24265,"load":{"average":6.77,"cores":14},"batch":{"ms":23914},"invariants":[{"component":"src/adapters","name":"a Rust file declares its top-level items","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23914,"reason":"1 test under \"a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":20,"mode":"batched","state":"invariant","enforces":["a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing"]},{"component":"src/adapters","name":"a Rust use is read in code alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23914,"reason":"1 test under \"a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":2,"mode":"batched","state":"invariant","enforces":["a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read"]},{"component":"src/adapters","name":"a Rust use in an inline module is read from that module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23914,"reason":"1 test under \"a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":3,"mode":"batched","state":"invariant","enforces":["a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate"]},{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23914,"reason":"1 test under \"a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":13,"mode":"batched","state":"invariant","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused"]}]} +{"at":"2026-10-26T23:32:40.100Z","session":"ae41053f3d446b86f","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"f76b1e0","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":95287,"load":{"average":7.06,"cores":14},"invariants":[{"component":"src/adapters","name":"a Rust file declares its top-level items","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23839,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing"]},{"component":"src/adapters","name":"a Rust use is read in code alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23706,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read"]},{"component":"src/adapters","name":"a Rust use in an inline module is read from that module","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23828,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a use inside an inline module is read from that module: super leaves it before the file'\\''s own, a path still inside it leads to no other file, and a bare path there names a crate' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate"]},{"component":"src/plugins","name":"a path a group spells in pieces is read whole","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23882,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused"]}]} diff --git a/.coherence/runs/af6128b7afd884689.4da4c79c.jsonl b/.coherence/runs/af6128b7afd884689.4da4c79c.jsonl new file mode 100644 index 00000000..eb99d6e2 --- /dev/null +++ b/.coherence/runs/af6128b7afd884689.4da4c79c.jsonl @@ -0,0 +1,10 @@ +{"at":"2026-10-27T19:14:12.532Z","session":"af6128b7afd884689","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27467,"load":{"average":13.14,"cores":14},"batch":{"ms":27014},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27014,"reason":"1 of 1 tests under \"a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through\" failed: a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through","testMs":9,"mode":"batched","state":"structural defect","enforces":["a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through"]}]} +{"kind":"refutation","at":"2026-10-27T19:14:12.920Z","session":"af6128b7afd884689","agent":"general-purpose","component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","broke":"let a manifest fill the kept slot without the refusal, so it loads through the config (src/plugins/registry.ts dataProblems)","verdict":"fail","reason":"1 of 1 tests under \"a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through\" failed: a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:14:56.717Z","session":"af6128b7afd884689","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26756,"load":{"average":10.1,"cores":14},"batch":{"ms":26301},"invariants":[{"component":"src/plugins","name":"an ejected copy is told to eject again","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26301,"reason":"1 of 1 tests under \"a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch\" failed: a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch","testMs":6,"mode":"batched","state":"requirement","enforces":["a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch"]}]} +{"kind":"refutation","at":"2026-10-27T19:14:57.119Z","session":"af6128b7afd884689","agent":"general-purpose","component":"src/plugins","name":"an ejected copy is told to eject again","form":"totality oracle","broke":"told a plugin named as a bundled one nothing of its ejection, as any plugin is told (src/plugins/registry.ts handReadersRefused)","verdict":"fail","reason":"1 of 1 tests under \"a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch\" failed: a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:15:32.245Z","session":"af6128b7afd884689","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26761,"load":{"average":9.36,"cores":14},"batch":{"ms":26354},"invariants":[{"component":"src/plugins","name":"an interfaces table states facts alone","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":26354,"reason":"1 of 1 tests under \"an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser\" failed: an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser","testMs":5,"mode":"batched","state":"requirement","enforces":["an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser"]}]} +{"kind":"refutation","at":"2026-10-27T19:15:32.649Z","session":"af6128b7afd884689","agent":"general-purpose","component":"src/plugins","name":"an interfaces table states facts alone","form":"totality oracle","broke":"let an interfaces table that answers readings of its text load, unrefused (src/plugins/languages.ts statedFacts)","verdict":"fail","reason":"1 of 1 tests under \"an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser\" failed: an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:16:08.824Z","session":"af6128b7afd884689","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27229,"load":{"average":9.12,"cores":14},"batch":{"ms":26823},"invariants":[{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26823,"reason":"1 of 1 tests under \"plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name\" failed: plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name","testMs":76,"mode":"batched","state":"structural defect","enforces":["plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name"]}]} +{"kind":"refutation","at":"2026-10-27T19:16:09.281Z","session":"af6128b7afd884689","agent":"general-purpose","component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","broke":"let a type declaration pass whether or not the interfaces reading of its line and the declares reading of the whole text agree (src/plugins/check.ts answersAgree)","verdict":"fail","reason":"1 of 1 tests under \"plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name\" failed: plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:17:10.714Z","session":"af6128b7afd884689","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":54751,"load":{"average":11.3,"cores":14},"batch":{"ms":52581},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52581,"reason":"1 test under \"a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":32,"mode":"batched","state":"invariant","enforces":["a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through"]},{"component":"src/plugins","name":"an ejected copy is told to eject again","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52581,"reason":"1 test under \"a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":6,"mode":"batched","state":"invariant","enforces":["a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch"]},{"component":"src/plugins","name":"an interfaces table states facts alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52581,"reason":"1 test under \"an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":30,"mode":"batched","state":"invariant","enforces":["an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser"]},{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":52581,"reason":"1 test under \"plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<4 names> src/**/*.test.ts src/*.e2e.ts","testMs":167,"mode":"batched","state":"invariant","enforces":["plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name"]}]} +{"at":"2026-10-27T19:18:56.735Z","session":"af6128b7afd884689","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":105555,"load":{"average":19.23,"cores":14},"invariants":[{"component":"src/plugins","name":"a language read through a parser has one reader of its text","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26505,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a manifest that fills a hand-written reader slot \\(source, declares, topLevel or kept\\) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through"]},{"component":"src/plugins","name":"an ejected copy is told to eject again","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25962,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a copy ejected from Coherence 1\\.10\\.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch"]},{"component":"src/plugins","name":"an interfaces table states facts alone","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26443,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='an interfaces table states its language'\\''s facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser"]},{"component":"src/plugins","name":"two slots that answer one question agree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26599,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration'\\''s kind from what surrounds it, so its line read alone says otherwise, named by file and name' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name"]}]} diff --git a/.coherence/runs/af6680f06b4959bd8.14b51916.jsonl b/.coherence/runs/af6680f06b4959bd8.14b51916.jsonl new file mode 100644 index 00000000..6439629a --- /dev/null +++ b/.coherence/runs/af6680f06b4959bd8.14b51916.jsonl @@ -0,0 +1,22 @@ +{"at":"2026-10-27T19:18:05.298Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":31054,"load":{"average":31.69,"cores":14},"batch":{"ms":30480},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30480,"reason":"1 test under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":344,"mode":"batched","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30480,"reason":"1 test under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":729,"mode":"batched","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/spec","name":"a practice fires on a defect's class","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":30480,"reason":"1 test under \"a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":78,"mode":"batched","state":"requirement","enforces":["a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30480,"reason":"1 test under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":2072,"mode":"batched","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":30480,"reason":"1 test under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":1072,"mode":"batched","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"at":"2026-10-27T19:20:20.572Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":134783,"load":{"average":11.84,"cores":14},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26765,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27267,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/spec","name":"a practice fires on a defect's class","form":"totality oracle","verdict":"pass","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":25886,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"requirement","enforces":["a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27697,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human'\\''s acknowledgement answers it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":27127,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"at":"2026-10-27T19:23:57.033Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26326,"load":{"average":15.22,"cores":14},"batch":{"ms":25913},"invariants":[{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25913,"reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","testMs":927,"mode":"batched","state":"structural defect","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]}]} +{"kind":"refutation","at":"2026-10-27T19:23:57.444Z","session":"af6680f06b4959bd8","agent":"general-purpose","component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","broke":"made deadEnds count only a subsystem's defects closed under a guard, so open and decided ones count for nothing, as the returns rule let them","verdict":"fail","reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:24:39.043Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":27209,"load":{"average":13.57,"cores":14},"batch":{"ms":26771},"invariants":[{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26771,"reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","testMs":1949,"mode":"batched","state":"structural defect","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]}]} +{"kind":"refutation","at":"2026-10-27T19:24:39.402Z","session":"af6680f06b4959bd8","agent":"general-purpose","component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","broke":"let any acknowledgement answer a dead end's escalation, an agent's without --human included, so it restarts the count","verdict":"fail","reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:25:27.684Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":26739,"load":{"average":11.36,"cores":14},"batch":{"ms":26237},"invariants":[{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":26237,"reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","testMs":1168,"mode":"batched","state":"structural defect","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]}]} +{"kind":"refutation","at":"2026-10-27T19:25:28.099Z","session":"af6680f06b4959bd8","agent":"general-purpose","component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","broke":"counted the unclassified defects together as one class, so a subsystem whose later defects all carry no class stays under the class threshold","verdict":"fail","reason":"1 of 1 tests under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" failed: spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:26:02.063Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":25776,"load":{"average":9.59,"cores":14},"batch":{"ms":25379},"invariants":[{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":25379,"reason":"1 of 1 tests under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" failed: converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed","testMs":925,"mode":"batched","state":"structural defect","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"kind":"refutation","at":"2026-10-27T19:26:02.368Z","session":"af6680f06b4959bd8","agent":"general-purpose","component":"src/spec","name":"converging work is no dead end","form":"totality oracle","broke":"dropped the rise threshold from deadEnds, so a component past the defect, class and round thresholds is named whether its arrivals rise or fall","verdict":"fail","reason":"1 of 1 tests under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" failed: converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:26:35.014Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24663,"load":{"average":8.09,"cores":14},"batch":{"ms":24300},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24300,"reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","testMs":171,"mode":"batched","state":"structural defect","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]}]} +{"kind":"refutation","at":"2026-10-27T19:26:35.326Z","session":"af6680f06b4959bd8","agent":"general-purpose","component":"src/journal","name":"a defect names its component","form":"totality oracle","broke":"made the defect verb accept a --component that another component's files contradict, refusing only files in no component","verdict":"fail","reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:27:08.694Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24708,"load":{"average":10.86,"cores":14},"batch":{"ms":24321},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24321,"reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","testMs":216,"mode":"batched","state":"structural defect","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]}]} +{"kind":"refutation","at":"2026-10-27T19:27:09.013Z","session":"af6680f06b4959bd8","agent":"general-purpose","component":"src/journal","name":"a defect names its component","form":"totality oracle","broke":"let the defect verb pass over a file in no component, so a defect naming widget/knob.ts and NOTES.md is written as widget's","verdict":"fail","reason":"1 of 1 tests under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" failed: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:27:41.937Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24937,"load":{"average":9.08,"cores":14},"batch":{"ms":24574},"invariants":[{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24574,"reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","testMs":359,"mode":"batched","state":"structural defect","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]}]} +{"kind":"refutation","at":"2026-10-27T19:27:42.239Z","session":"af6680f06b4959bd8","agent":"general-purpose","component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","broke":"made loadJournalAcrossWorktrees skip a store file whose length equals one already read, without comparing its bytes, as the name and size skip did","verdict":"fail","reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:28:18.755Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28572,"load":{"average":10.89,"cores":14},"batch":{"ms":28203},"invariants":[{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"fail","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28203,"reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","testMs":375,"mode":"batched","state":"structural defect","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]}]} +{"kind":"refutation","at":"2026-10-27T19:28:19.162Z","session":"af6680f06b4959bd8","agent":"general-purpose","component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","broke":"made otherWorktrees keep a worktree git calls prunable, so a folder whose checkout git no longer knows is read","verdict":"fail","reason":"1 of 1 tests under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" failed: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:28:52.036Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":24760,"load":{"average":28.17,"cores":14},"batch":{"ms":24350},"invariants":[{"component":"src/spec","name":"a practice fires on a defect's class","form":"totality oracle","verdict":"fail","refutation":"missing","bypasses":[],"testReferences":0,"files":[],"latency":24350,"reason":"1 of 1 tests under \"a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text\" failed: a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text","testMs":2,"mode":"batched","state":"requirement","enforces":["a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text"]}]} +{"kind":"refutation","at":"2026-10-27T19:28:52.335Z","session":"af6680f06b4959bd8","agent":"general-purpose","component":"src/spec","name":"a practice fires on a defect's class","form":"totality oracle","broke":"made a defect trigger read --class from any simple command, not only Coherence's defect, classify and resolved verbs","verdict":"fail","reason":"1 of 1 tests under \"a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text\" failed: a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text","commit":"2558929","dirty":true} +{"at":"2026-10-27T19:29:27.658Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":28559,"load":{"average":18.5,"cores":14},"batch":{"ms":28040},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28040,"reason":"1 test under \"a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":271,"mode":"batched","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28040,"reason":"1 test under \"the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":601,"mode":"batched","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/spec","name":"a practice fires on a defect's class","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28040,"reason":"1 test under \"a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":64,"mode":"batched","state":"invariant","enforces":["a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28040,"reason":"1 test under \"spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":1952,"mode":"batched","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":28040,"reason":"1 test under \"converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed\" passed in one invocation of node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-reporter=./src/enforcement/node-test-reporter.ts --test-reporter-destination= --test-name-pattern=<5 names> src/**/*.test.ts src/*.e2e.ts","testMs":914,"mode":"batched","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} +{"at":"2026-10-27T19:31:29.649Z","session":"af6680f06b4959bd8","agent":"general-purpose","binding":"none: this session owns no active work order","commit":"2558929","dirty":true,"instrument":{"language":"typescript","server":"none"},"latency":121658,"load":{"average":7.07,"cores":14},"invariants":[{"component":"src/journal","name":"a defect names its component","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24556,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so"]},{"component":"src/journal","name":"the journal is read from every worktree","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24633,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading"]},{"component":"src/spec","name":"a practice fires on a defect's class","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":23507,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["a defect trigger fires on a command that records, classifies or closes a defect in its class or family, and on no other class, verb or quoted text"]},{"component":"src/spec","name":"a subsystem at a dead end is named","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24861,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human'\\''s acknowledgement answers it' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it"]},{"component":"src/spec","name":"converging work is no dead end","form":"totality oracle","verdict":"pass","refutation":"witnessed","bypasses":[],"testReferences":0,"files":[],"latency":24071,"reason":"node --disable-warning=ExperimentalWarning --import=./src/enforcement/leak-guard.ts --test --test-concurrency=1 --test-name-pattern='converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed' 'src/**/*.test.ts' 'src/*.e2e.ts' exited 0 and its output matched /# pass [1-9][0-9]*/","mode":"one-at-a-time","state":"invariant","enforces":["converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed"]}]} diff --git a/.coherence/work/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.fced0e1c.jsonl b/.coherence/work/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.fced0e1c.jsonl new file mode 100644 index 00000000..429c80e6 --- /dev/null +++ b/.coherence/work/43578eac-3b0b-4f22-bfa7-acd0b90b46d0.fced0e1c.jsonl @@ -0,0 +1,8 @@ +{"id":"w-4c76c5ea","kind":"order","at":"2026-10-27T15:59:55.789Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"objective":"the Journal tab aggregates the journal of every worktree of the project, not only the checkout the session started in","success":"with a session's records in a linked worktree's .coherence/journal (git worktree list) and none in the main checkout, opening the Journal tab shows them, each named by the worktree it came from, and a record written in either appears while the tab is open","boundary":"mods/coherence/hooks","owner":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0"} +{"id":"w-8e253e9e","kind":"order","at":"2026-10-27T16:04:03.949Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"objective":"the plugin interface has no hand-written reader slots: source, declares, topLevel and kept are gone from pluginApi 4, a plugin filling one is refused naming the slot and treeSitter, and no core code reads them","success":"npm test passes; a plugin manifest filling syntax.source, declares, topLevel or kept is refused with a message naming the slot and treeSitter; a parse-based test fails if core code reads any of the four; every bundled plugin passes plugin check","boundary":"src/plugins, src/economy, src/readings, src/cli.e2e.ts, plugins, docs/plugins.md","owner":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0"} +{"id":"w-d112a3e4","kind":"order","at":"2026-10-27T17:53:14.624Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"objective":"the version of every bundled plugin and mod that follows the package is written from package.json by the build, never kept by hand","success":"npm pack and the prerelease read one version, a manifest holds none that can differ, and the prerelease version checks are gone","boundary":"package.json, plugins/*/plugin.json, mods/*/.claude-plugin/plugin.json, src/build.ts, src/lifecycle/prerelease.ts","owner":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0"} +{"id":"w-f50ec192","kind":"order","at":"2026-10-27T17:53:14.895Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"objective":"a bullet's refuted lines are generated from the run records that witness them, or dropped, so no refutation is written twice","success":"spec --check shows each refutation from its run record, and a refuted: line no record holds is a problem","boundary":"src/spec, src/enforcement, docs/spec.md","owner":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0"} +{"id":"w-7f9dbfb0","kind":"order","at":"2026-10-27T17:53:15.171Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"objective":"a number in a document or a decision names the command that measured it, and the bench job measures it again","success":"docs/plugins.md's numbers each carry their command, and a stale one fails the bench job","boundary":"docs, bench, .github/workflows/ci.yml","owner":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0"} +{"id":"w-77d2fe8f","kind":"order","at":"2026-10-27T17:53:15.436Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"objective":"the structure reading stops by questions counted, not seconds, so the same checkout gives the same answer whatever the machine's load, and a partial reading names what it did not ask","success":"query structure over PostHog gives the same counts twice under different load, and names the declarations it did not ask","boundary":"src/readings/scope, src/adapters","owner":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0"} +{"id":"w-fdc00207","kind":"order","at":"2026-10-27T17:59:53.780Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"objective":"a defect whose guard is demoted can be closed again under a new guard or a decision, so retiring a bullet never leaves its closes with neither","success":"after a demote decision, resolved --guard --supersedes is accepted and spec --check names no close with neither for it; df-04fddaf1 re-guarded by src/plugins/the parse store never reaches past the project's own folders","boundary":"src/journal","owner":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0"} +{"id":"w-9c70b73f","kind":"order","at":"2026-10-27T18:08:40.772Z","session":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0","agent":"main","commit":"887abd8","dirty":true,"objective":"practice delivery attributes a command to the session that ran it, so a subagent's command in its own worktree is owed by that subagent's session, never its parent's","success":"a subagent's lexicon apply, refute or defect in its own worktree asks no enactment of the parent session at its stop; the subagent's own stop asks it, and an enactment it records answers it","boundary":"src/lifecycle, src/journal","owner":"43578eac-3b0b-4f22-bfa7-acd0b90b46d0"} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b56f56c3..8bffcf96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,6 +83,37 @@ jobs: COHERENCE_TEST_SHARD: ${{ matrix.shard }}/2 run: npm run test:unit + # The TypeScript plugin's two parsers, rebuilt from tree-sitter-typescript + # 0.23.2 and Coherence's patch (grammars/tree-sitter-typescript). The fetch + # phase downloads every input and checks it by digest; the build phase runs + # in a container with no network (docker --network none, which is what + # denies it; the phase's own connection attempt is a tripwire), checks every + # input again, builds from the pinned upstream tree, refuses a patch that + # changes anything but the grammar and its scanner, runs upstream's corpus + # from that clean tree and Coherence's from corpus/ (outside the patch), + # builds the stock and patched parsers, fails on any difference between + # what they read that intended-differences.json does not allow and on any + # expected tree the patched parsers do not read (compare.mjs), and fails + # unless each patched parser comes out byte for byte as parsers.sha256 + # records. The image is inputs.sh's build_image, pinned by digest. + typescript-parsers: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Fetch the pinned inputs + run: grammars/tree-sitter-typescript/fetch.sh "$RUNNER_TEMP/grammar-inputs" + + - name: Build both parsers with no network and compare them with the stock ones + run: | + . grammars/tree-sitter-typescript/inputs.sh + docker run --rm --network none \ + --volume "$GITHUB_WORKSPACE:/repo:ro" --volume "$RUNNER_TEMP/grammar-inputs:/inputs:ro" \ + "$build_image" /repo/grammars/tree-sitter-typescript/build-phase.sh /inputs /tmp/parsers + # Everything in npm test but the unit tests, beside them, and the chokepoint run. checks: runs-on: ubuntu-latest @@ -130,10 +161,10 @@ jobs: - name: Chokepoints run: node --disable-warning=ExperimentalWarning src/cli.ts run --form chokepoint --no-server --session "ci-${{ github.run_id }}" --agent ci - # One check that stands for the rest: green only when every shard and the checks are. + # One check that stands for the rest: green only when every shard, the checks and the parsers' build are. verify: if: always() - needs: [unit, checks] + needs: [unit, checks, typescript-parsers] runs-on: ubuntu-latest steps: - name: Every shard and check passed diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml new file mode 100644 index 00000000..89a25234 --- /dev/null +++ b/.github/workflows/prerelease.yml @@ -0,0 +1,143 @@ +# Cuts a prerelease of @posthog/coherence from a branch, before it merges: a +# GitHub prerelease carrying the package's tarball, and never npm, which +# release.yml publishes to from main alone, through the Release environment. +# Run it by hand, from the Actions tab or with +# +# gh workflow run prerelease.yml -f ref= -f notes="$(cat notes.md)" +# +# Two jobs. build, with read access alone, checks the branch out clean at its +# tip, with full history, so the tarball is packed from that commit and +# nothing else: no contributor's working tree, remote or local ref has a say +# in what ships, which is why cutting moved here from a local script whose +# view of them kept diverging from what would ship. Before it installs or +# packs, src/lifecycle/prerelease.ts refuses, naming each reason, unless the +# version is a prerelease that every bundled plugin and mod following the +# package names, the commit is on a branch of the repository package.json +# names and holds its main, and no tag of the version exists. It then packs +# the tarball, installs it in an empty folder and runs the TypeScript and +# Python plugins' checks from it, which read through their bundled parsers, +# and hands the tarball on as an artifact. release, the one job that can +# write, creates the version's tag at the commit build checked out, by its +# sha, never the branch's name, which may move while this runs (refused if +# the tag exists by then), and the prerelease on that tag, carrying the +# tarball. It checks nothing out and runs no code of the branch's. +# +# What this workflow does is held by how it is built and by its runs. The +# unit test only lints its shape: dispatched by hand alone, each job's +# permissions, every action pinned by commit. +name: Prerelease + +run-name: Prerelease of ${{ inputs.ref }} + +on: + workflow_dispatch: + inputs: + ref: + description: The branch to cut, at its tip when the run starts (a branch name, not a tag or a commit) + required: true + type: string + notes: + description: The release notes, in Markdown + required: true + type: string + +permissions: + contents: read + +# One prerelease at a time, so the tag the check finds free is still free when +# the release creates it. GitHub keeps one run pending behind the one running: +# a third dispatch cancels the pending second, which shows as cancelled before +# it has checked out anything, and is dispatched again. A run in progress is +# never cancelled, so no cut stops between its tag and its release. +concurrency: + group: prerelease + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: read + outputs: + sha: ${{ steps.commit.outputs.sha }} + version: ${{ steps.commit.outputs.version }} + steps: + # The branch by its full ref, so a tag or a commit is refused here; full history, so the check can read main's ancestry. + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: refs/heads/${{ inputs.ref }} + fetch-depth: 0 + persist-credentials: false + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: "22.18" + + # The commit released, resolved once: every later step, and the release job, names it by this sha. + - name: The commit and version cut + id: commit + run: | + echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT" + + - name: May this commit be cut? + run: node --disable-warning=ExperimentalWarning src/lifecycle/prerelease.ts + + # No dependency's install script runs here. + - run: npm ci --ignore-scripts + + # prepare builds dist; the tarball is checked before it is handed on. + - run: npm pack + + # The package as an adopter installs it, outside this checkout. Each copy of the TypeScript parsers it carries (the + # one the installed command loads, dist/bundled, and plugins/) must be byte for byte the digests parsers.sha256 + # records, the ones the build makes: a plugin check passes a stock or wrongly built parser that reads its fixtures. + # Then each plugin check reads its fixtures through the plugin's bundled parser and exits 1 on any check that fails, + # so a tarball missing a plugin or a parser fails here too. + - name: Check the tarball's parsers and that it reads TypeScript and Python + env: + VERSION: ${{ steps.commit.outputs.version }} + run: | + mkdir "$RUNNER_TEMP/smoke" && cd "$RUNNER_TEMP/smoke" + npm init -y >/dev/null + npm install --ignore-scripts "$GITHUB_WORKSPACE/posthog-coherence-$VERSION.tgz" + for parsers in node_modules/@posthog/coherence/dist/bundled/typescript node_modules/@posthog/coherence/plugins/typescript; do + (cd "$parsers" && shasum -a 256 -c "$GITHUB_WORKSPACE/grammars/tree-sitter-typescript/parsers.sha256") + done + npx --no coherence plugin check typescript + npx --no coherence plugin check python + + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: tarball + path: posthog-coherence-${{ steps.commit.outputs.version }}.tgz + if-no-files-found: error + retention-days: 7 + + release: + needs: build + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + # contents: write creates the tag and the release; nothing is published to npm, so no id-token. + contents: write + steps: + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: tarball + path: ${{ runner.temp }}/tarball + + # The tag is created at the sha build checked out, and creating a tag that exists fails, so the release is never + # made on a tag at another commit; --verify-tag then releases on that tag alone. The notes reach the shell through + # the environment, never spliced into the script. + - name: Create the GitHub prerelease + env: + GH_TOKEN: ${{ github.token }} + SHA: ${{ needs.build.outputs.sha }} + VERSION: ${{ needs.build.outputs.version }} + NOTES: ${{ inputs.notes }} + run: | + gh api --method POST "repos/$GITHUB_REPOSITORY/git/refs" -f "ref=refs/tags/v$VERSION" -f "sha=$SHA" >/dev/null + printf '%s\n' "$NOTES" > "$RUNNER_TEMP/notes.md" + gh release create "v$VERSION" --repo "$GITHUB_REPOSITORY" --verify-tag --prerelease --title "v$VERSION" --notes-file "$RUNNER_TEMP/notes.md" "$RUNNER_TEMP/tarball/posthog-coherence-$VERSION.tgz" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ad70629..ba0365c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,16 @@ # check job compares that version with npm's, and the publish job runs only # for a version npm does not have yet, so any other change to package.json # releases nothing. It can also be run by hand from the Actions tab. +# +# A prerelease cut from a branch, before it merges, is a GitHub prerelease with +# the tarball and never npm: prerelease.yml cuts it, run by hand +# (gh workflow run prerelease.yml -f ref= -f notes=...), from the +# branch checked out clean, and only when it holds main. +# +# A prerelease version (1.11.0-beta.0) publishes under its own dist-tag (beta), +# never latest, and its GitHub release is marked a prerelease: npm install +# @posthog/coherence and Coherence's update notice, which read latest, never +# reach it; npm install @posthog/coherence@beta does. name: Release on: @@ -83,9 +93,18 @@ jobs: npm install --ignore-scripts "$GITHUB_WORKSPACE"/posthog-coherence-*.tgz npx --no coherence spec --check - - run: npm publish posthog-coherence-*.tgz --access public --provenance + # A prerelease publishes under its identifier's tag (1.11.0-beta.0 under beta); any other version under latest. + - name: Publish + run: | + tag=latest + # The prerelease identifier's leading letters (beta.1 -> beta, alpha-2.3 -> alpha, rc.2 -> rc); next when it has none (1.11.0-0). + case "$VERSION" in *-*) tag=$(printf '%s' "${VERSION#*-}" | sed 's/[^A-Za-z].*$//'); [ -n "$tag" ] || tag=next ;; esac + npm publish posthog-coherence-*.tgz --access public --provenance --tag "$tag" - name: Tag the release on GitHub env: GH_TOKEN: ${{ github.token }} - run: gh release create "v$VERSION" --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" --title "v$VERSION" --generate-notes + run: | + prerelease="" + case "$VERSION" in *-*) prerelease=--prerelease ;; esac + gh release create "v$VERSION" --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" --title "v$VERSION" --generate-notes $prerelease diff --git a/README.md b/README.md index 6068d059..67251095 100644 --- a/README.md +++ b/README.md @@ -413,7 +413,9 @@ test setup per runner, as [docs/config.md](docs/config.md#more-than-one-language Rust chokepoints are graded through rust-analyzer, found on the machine rather than installed by npm ([docs/enforcement.md](docs/enforcement.md#rust)); the economy and Scope readings read Rust's text by its crates' folder layout, and detect its -binaries, build scripts, routes and foreign exports as entrances. +binaries, examples, build scripts, routes and foreign exports (C, wasm-bindgen and +UniFFI, an exported impl's methods among them) as entrances; a declared mirror +reads a Rust list from the array a const or static is set to. Go is an opt-in bundled plugin, `"plugins": { "go": "bundled" }`, graded through gopls ([docs/plugins.md](docs/plugins.md#go)); a language Coherence lacks is a plugin you can write, held by `coherence plugin check` to what every @@ -635,6 +637,25 @@ environment, with provenance and no stored token, and tags it as a GitHub release with generated notes. Any other change to package.json releases nothing. The workflow can also be run by hand from the Actions tab. +A prerelease of a branch, before it merges, is a GitHub prerelease carrying +the tarball, never npm. Bump the versions as above to a prerelease +(`1.11.0-beta.4`), merge main into the branch, push it, and run the +Prerelease workflow: + +```sh +gh workflow run prerelease.yml -f ref= -f notes="$(cat notes.md)" +``` + +`.github/workflows/prerelease.yml` checks the branch out clean at its tip, +with read access alone, and refuses (naming each reason) unless the version is +a prerelease that every bundled plugin and mod following the package names, +the commit is on a branch of PostHog/coherence and holds its main, and no tag +of the version exists; then it packs the tarball there, installs it in an +empty folder and runs `coherence plugin check typescript` and `plugin check +python` from it. A second job, the only one that can write, tags that +commit's sha and creates the prerelease on the tag, carrying the tarball. +Nothing is cut from a local checkout. + ## Further reading - `Coherence.spec.md` and the `*.spec.md` file in each folder under `src/`: Coherence's own trust levels and invariants, in its own grammar. diff --git a/bench/interfaces/own-tree.ts b/bench/interfaces/own-tree.ts index 3c97c5af..8ff25937 100644 --- a/bench/interfaces/own-tree.ts +++ b/bench/interfaces/own-tree.ts @@ -12,6 +12,10 @@ import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { TypeScriptAdapter } from "../../plugins/typescript/typescript.ts"; import { bothWays, sameMap } from "../../src/readings/scope/both-ways.ts"; +import { startParsers } from "../../src/plugins/syntax-trees.ts"; + +// A reading through a language's parser needs its runtime started first, as the CLI starts it. +await startParsers(); const root = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); const started = performance.now(); diff --git a/bench/mirrors/score.ts b/bench/mirrors/score.ts index 772c1401..bcae771b 100644 --- a/bench/mirrors/score.ts +++ b/bench/mirrors/score.ts @@ -17,6 +17,10 @@ import { fileURLToPath } from "node:url"; import { readMirrors } from "../../src/readings/mirrors/mirrors.ts"; import type { Group, SetRef } from "../../src/readings/mirrors/model.ts"; import { alarmsOf, alarmText, surfaced } from "../../src/readings/mirrors/policy.ts"; +import { startParsers } from "../../src/plugins/syntax-trees.ts"; + +// A reading through a language's parser needs its runtime started first, as the CLI starts it. +await startParsers(); const here = dirname(fileURLToPath(import.meta.url)); const argv = process.argv.slice(2); diff --git a/bench/records/github-counts.ts b/bench/records/github-counts.ts index 2cca4560..6f78163f 100644 --- a/bench/records/github-counts.ts +++ b/bench/records/github-counts.ts @@ -28,6 +28,10 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { STORE_NAMES, storeDir } from "../../src/journal/stores.ts"; +import { startParsers } from "../../src/plugins/syntax-trees.ts"; + +// A reading through a language's parser needs its runtime started first, as the CLI starts it. +await startParsers(); const REPO = resolve(dirname(fileURLToPath(import.meta.url)), "..", ".."); const args = process.argv.slice(2); diff --git a/bench/records/layouts.ts b/bench/records/layouts.ts index 4bd3e9e0..34edf38e 100644 --- a/bench/records/layouts.ts +++ b/bench/records/layouts.ts @@ -36,6 +36,10 @@ import { STORE_NAMES, storeDir, type RecordStore } from "../../src/journal/store import { journalFileKeys, loadJournal } from "../../src/journal/store.ts"; import { loadWork } from "../../src/journal/work.ts"; import { ATTRIBUTES_TEXT } from "../../src/lifecycle/state-files.ts"; +import { startParsers } from "../../src/plugins/syntax-trees.ts"; + +// A reading through a language's parser needs its runtime started first, as the CLI starts it. +await startParsers(); const REPO = resolve(dirname(fileURLToPath(import.meta.url)), "..", ".."); const args = process.argv.slice(2); diff --git a/bench/records/shipped.ts b/bench/records/shipped.ts index 37aa06a6..d4a8345e 100644 --- a/bench/records/shipped.ts +++ b/bench/records/shipped.ts @@ -27,6 +27,10 @@ import type { Decision } from "../../src/journal/record.ts"; import { shardFor } from "../../src/journal/shards.ts"; import { appendRecord, loadJournal } from "../../src/journal/store.ts"; import { isStoreFile } from "../../src/journal/stores.ts"; +import { startParsers } from "../../src/plugins/syntax-trees.ts"; + +// A reading through a language's parser needs its runtime started first, as the CLI starts it. +await startParsers(); const REPO = resolve(dirname(fileURLToPath(import.meta.url)), "..", ".."); const EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"; diff --git a/bench/scale/run.ts b/bench/scale/run.ts index 7c4f397c..9dd79741 100644 --- a/bench/scale/run.ts +++ b/bench/scale/run.ts @@ -28,6 +28,10 @@ import { parseArgs } from "node:util"; import { generate, LEAVES } from "./generate.ts"; import { TOOL_HOOKS } from "../../src/lifecycle/hook-events.ts"; import { DEFAULT_LATENCY_BUDGET } from "../../src/lifecycle/hook-latency.ts"; +import { startParsers } from "../../src/plugins/syntax-trees.ts"; + +// A reading through a language's parser needs its runtime started first, as the CLI starts it. +await startParsers(); const CLI = fileURLToPath(new URL("../../src/cli.ts", import.meta.url)); const BUDGETS = fileURLToPath(new URL("./budgets.json", import.meta.url)); diff --git a/bench/scope/own-tree.ts b/bench/scope/own-tree.ts index e33227a3..4fc09759 100644 --- a/bench/scope/own-tree.ts +++ b/bench/scope/own-tree.ts @@ -1,6 +1,6 @@ /** * The Scope page over Coherence's own tree: it builds to the default path and - * stays under 3 MB with every component, run and journal record embedded or + * stays under 5 MB with every component, run and journal record embedded or * counted, and its first load carries at most the site window's reference * sites while every latest verdict and every chokepoint's sites read as the * whole runs give them. The unit suite proves both on fixtures @@ -22,18 +22,22 @@ import { SITE_WINDOW, latestOf, sitesLeftCount } from "../../src/readings/scope/ import type { LatestEntry, ShellState } from "../../src/readings/scope/model.ts"; import { flowOf } from "../../src/readings/scope/structure-flow.ts"; import { loadSpecModel } from "../../src/spec/model.ts"; +import { startParsers } from "../../src/plugins/syntax-trees.ts"; + +// A reading through a language's parser needs its runtime started first, as the CLI starts it. +await startParsers(); const root = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); process.chdir(root); const started = performance.now(); const options: BuildOptions = { lexiconPath: DEFAULTS.lexiconPath, project: DEFAULTS.project }; -const THREE_MB = 3 * 1024 * 1024; +const FIVE_MB = 5 * 1024 * 1024; -// The page builds to the default path and stays under 3 MB with Coherence's own data. +// The page builds to the default path and stays under 5 MB with Coherence's own data. const { bytes, state } = await writeScopePage(options, DEFAULTS.outPath); const onDisk = await readFile(DEFAULTS.outPath, "utf8"); assert.equal(Buffer.byteLength(onDisk, "utf8"), bytes); -assert.ok(bytes < THREE_MB, `page is ${bytes} bytes, must be under ${THREE_MB}`); +assert.ok(bytes < FIVE_MB, `page is ${bytes} bytes, must be under ${FIVE_MB}`); assert.equal(state.spec.components.length, loadSpecModel(root).components.length, "every component of Coherence's own tree is in the state"); assert.equal(state.runs.records.length + (state.runs.omitted ?? 0), loadRuns(root).records.length, "every run record is embedded or counted"); assert.equal(state.journal.records.length + (state.journal.omitted ?? 0), loadJournal(root).records.length, "every journal record is embedded or counted"); diff --git a/docs/journal.md b/docs/journal.md index 78e09532..34d8def3 100644 --- a/docs/journal.md +++ b/docs/journal.md @@ -17,7 +17,7 @@ absent. A single-value flag given twice is refused. - `resolved --because "" [--as ""]`: resolves a conjecture. - `resolved --because "" [--guard /] [--decision ]`: closes a defect (see Defects below). - `dismiss --because ""` -- `defect "" --evidence "" [--file ]... [--class ] [--introduced ] [--caught ] [--cite ]...` +- `defect "" --evidence "" (--file ... [--component ] | --component | --unplaced "") [--class ] [--introduced ] [--caught ] [--cite ]...` - `classify [--class ] [--introduced <...>] [--caught <...>] --because ""`: a decision citing the defect that gives the fields it lacked. - `experiment create "" [--context ]... --action ""... --success ""... [--cite ]...`: prints step ids. - `experiment close --result =...`: every step needs a result; the outcome is derived. @@ -57,6 +57,16 @@ fields, which the practice close a defect asks for: pull request makes the defect fix-induced. - `caught`: review, ci, probe, adopter, self or test. +A defect says where it lies: `--file` for each file of the fault, or +`--component `, or, only when no file or component of the project +holds it, `--unplaced ""`; with none of them the verb refuses and says +what to pass, since a defect placed nowhere counts toward no dead end. It +names its `component`, the folder of the spec it belongs to: `--component +`, or, without it, the one component whose folder holds every file +`--file` names, each path read with its `.` and `..` resolved. Files in +several components, or none, write no component, and the verb says how to +name one. + A defect recorded without them stays valid. The journal is append-only, so `classify` gives them later as a decision citing the defect; every reader folds the defect's own fields, then each classification not retracted, then @@ -70,11 +80,30 @@ is a guard failure: the guard was weaker than claimed. Both are advisory, and orient lists each guard failure. A retracted close no longer closes, so a defect can be closed again with its guard. +A dead end is a component whose defects keep coming back after it was +guarded: within the last 14 days and since the first close of one of its +defects with a witnessed guard, 8 or more defects across 3 or more classes or +families, recorded at 3 or more commits (a round's findings share the commit +its fixes land on), 3 or more of them closed by a guard that had already closed +an earlier defect there. Its guards are narrowing doors in a design that is +wrong. `spec --check`, orient and the convergence reading name each dead end +with its defects, classes, rounds, first guard and window, and say what to +do: stop adding guards there, review its representation, record the choice as +a decision, and `escalate` the question to a human, citing one of its defects. +The escalation then heads every read; a human's `acknowledge` restarts the +count, so a component that keeps failing after the answer is named again. +Coherence never writes the escalation itself: a record carries the session +that wrote it, and a reading writes none. The reading reads the journal of +every worktree of the repository, each record once, and says how many it read +and how it placed each defect: by the component its record names, or, for a +record older than the field, by its files, else its guard's component. It is +advisory and never a problem. + `query convergence [--days ] [--json]` reads whether discoveries repay over a window (14 days by default): defects arriving by origin and catch, escapes -per release, the share closed with a guard, repeats per class, bullets at each -day and release tag, the files most often changed, and hook latency p50 and -p95 per event and Coherence version. +per release, the share closed with a guard, repeats per class, dead ends, +bullets at each day and release tag, the files most often changed, and hook +latency p50 and p95 per event and Coherence version. `query mirrors [--all] [--rev ] [--json | --proposals]` is the mirror reading: the lists kept by hand that must mirror another list, a folder or the diff --git a/docs/lexicon.json b/docs/lexicon.json index 22dbbc59..5f732d51 100644 --- a/docs/lexicon.json +++ b/docs/lexicon.json @@ -604,21 +604,17 @@ "guard": "The invariant a defect's close names, as /, to protect the defect's whole class; it counts once its refutation is witnessed. A close names a guard or a decision saying why fixing the instance suffices; spec --check names a close with neither.", "guard failure": "A defect recorded in a class a close had already guarded, after that close: the protection was weaker than claimed. spec --check and orient name it; the convergence reading counts it as a repeat of its class, which should fall to zero.", "escape": "A defect whose introduced points into a release's range and that was recorded after the release's tag: it shipped.", - "convergence": "The reading of whether discoveries repay, over a window: defects arriving by origin and catch, escapes per release, the share closed with a guard, repeats per class, bullets over time, hotspot churn, and hook latency per Coherence version (query convergence).", + "convergence": "The reading of whether discoveries repay, over a window: defects arriving by origin and catch, escapes per release, the share closed with a guard, repeats per class, dead ends, bullets over time, hotspot churn, and hook latency per Coherence version (query convergence).", "class path-identity": "One file or folder spelled two ways (through a symbolic link, against another base, from the repository top instead of the project root) compares as two.", - "class cost": "Work out of proportion to the answer: a hook or reading that reads far more than it needs, past the latency budget.", "class ownership": "One party's thing treated as another's: Coherence's lexicon, practice or decision demanded of or read as an adopter's, or the reverse.", "class structure-drift": "What a spec, the lexicon or a document says has drifted from what the code or the files do, and no check sees it.", "class bypassed-door": "A reference reaches a protected thing outside its chokepoint.", - "class parse-gap": "A reader of source, shell or spec text misses a shape its language allows.", "class root-resolution": "The tool settled on the wrong project root, so it read, wrote or answered for the wrong tree.", "class overmatch": "A pattern or check matches more than it means, so an unrelated thing satisfies or triggers it.", "class self-clearing": "A check the very record or edit it guards can clear on its own.", "class exposure": "Private state written where it is published or committed.", "class uninterpolated": "Template text reaches a reader literally instead of the value it stands for.", "class load-flake": "A test that fails under machine load whatever the change under test.", - "class duplicated-fact": "One fact kept in two places written apart, so one copy drifts from the other and a reader takes the stale one.", - "class over-claim": "A reading credits more than its evidence shows: a control, a coverage or a verification counted where nothing checks it, so a gap reads closed.", "class hand-built-path": "A file of an installed package located by a path spelled by hand (a node_modules folder joined to a root) instead of asked of the package resolver, so a package manager that lays its packages out otherwise (pnpm's store, a package's exports) leaves it naming nothing.", "class missing-entry-point": "A way of reaching the tool that users expect is absent or answers wrongly: a conventional flag or verb (--version, --help) that is not recognized or is taken by the program in front of it.", "class false-alarm": "A check reports a problem on input that is valid, such as a config, spec or lexicon an adopter wrote correctly or an earlier release wrote for it, so it fails CI or refuses a stop for nothing; guarded by the upgrade fixture carrying what adopters write.", @@ -627,7 +623,13 @@ "family hand-list": "A list kept by hand that must mirror something defined elsewhere (files, imports, events, tools, keys), so the two drift and nothing fails: a module, an event or a tool silently left out. A family: each list is removed by deriving it from what it mirrors, one guard per list.", "family silent-skip": "A reading, walk or command leaves part of what it was given out and says nothing about it. A family: every reader and command can skip in its own way, so each defect closes with its own guard or a decision, and a later one is no guard failure.", "mirror reading": "The reading that finds hand lists: literal collections of names matched by overlap against each other and against what code derives (a folder's files, the import closure of a list of files, a module's exports, the keys a file reads), from git objects at one revision, with history naming the commit that grew one side alone (query mirrors). Advisory and never taken in a hook: orient names the groups worth a look from the last reading kept, and the reading proposes pairs for the edit-time alarm to watch.", - "family version-skew": "The Coherence that runs is not the one the adopter installed or meant: another copy shadows it, a package manager resolved an older release than the project needs, or a plugin's import reaches another copy than the running one, and nothing says which version answers. A family: every place that picks a copy (which launches, which installs, which a plugin imports) picks it in its own way, so each defect closes with its own guard or a decision, and a later one is no guard failure." + "family version-skew": "The Coherence that runs is not the one the adopter installed or meant: another copy shadows it, a package manager resolved an older release than the project needs, or a plugin's import reaches another copy than the running one, and nothing says which version answers. A family: every place that picks a copy (which launches, which installs, which a plugin imports) picks it in its own way, so each defect closes with its own guard or a decision, and a later one is no guard failure.", + "family parse-gap": "A reader of source, shell or spec text misses a shape its language allows. A family: every hand-written reader (entrance rules, the shell reader, a plugin's import reader) misses shapes in its own way, so each defect closes with its own guard or a decision, and a later one is no guard failure; a reader moved onto a parser leaves it for that parser's guards.", + "family cost": "Work out of proportion to the answer: a hook or reading that reads far more than it needs, past the latency budget. A family: every hook, reading and store pays its own way (the dead-trigger check's triggers, a parse store kept per leaf of a registry), so each defect closes with its own guard or a decision, and a later one is no guard failure.", + "family duplicated-fact": "One fact kept in two places written apart, so one copy drifts from the other and a reader takes the stale one. A family: every fact can be kept twice in its own way (the project's name in the config and a lexicon, a parse's inputs in a manifest and a fingerprint), so each defect closes with its own guard or a decision, and a later one is no guard failure.", + "family over-claim": "A reading credits more than its evidence shows: a control, a coverage, a verification or a defense counted where nothing checks it, so a gap reads closed. A family: every reading, test and claimed defense can over-claim in its own way (a scope's test-backed control, a parse store's signature and its untested clauses), so each defect closes with its own guard or a decision, and a later one is no guard failure.", + "component": "The component a defect belongs to, as its folder: given with --component, or settled when the defect is written as the one component whose folder holds every file it names. A record written before the field, or whose files lie in several components, carries none; the dead-end reading then places it by its files, else by its guard's component, and says how many it placed that way and how many it could not.", + "dead end": "A component that keeps collecting defects after its first guard, across classes and families, over several rounds (the commits they were recorded at), with defects coming back through guards it already had, within the convergence window: its guards are narrowing doors in a design that is wrong. spec --check, orient and the convergence reading name it with its defects, classes, rounds and window, read from every worktree's journal; the remedy is to stop adding guards there, review its representation, record the choice as a decision, and escalate it to a human, whose acknowledgement restarts the count." } }, { @@ -932,7 +934,7 @@ { "name": "orient", "status": "settled", - "definition": "The start-of-cycle reading. Before acting, the session sees where the project stands and what heading follows from it. It shows escalations awaiting a human, structural defects, requirements stuck short of invariant, unreached mass, the session's own work order, and what peers recorded. One heading, derived from state; it also names the spec gaps beyond the adoption baseline.", + "definition": "The start-of-cycle reading. Before acting, the session sees where the project stands and what heading follows from it. It shows escalations awaiting a human, structural defects, dead ends and guard failures, requirements stuck short of invariant, unreached mass, the session's own work order, and what peers recorded. One heading, derived from state; it also names the spec gaps beyond the adoption baseline.", "rejected": [ { "alternative": "orient and regulate as two competing machines over the same ledgers", diff --git a/docs/plugins.md b/docs/plugins.md index e77e4405..6e2fb650 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -114,9 +114,18 @@ project's other files resolve the package as they always did. The installed copy still gives an editor and a typecheck the interface's types. The bundled plugins are the fullest examples, shipped in the package under -`plugins/`: `go` for a language Coherence lacks, `rust` for an adapter over a -language server with no npm package, `typescript`, `python` (with tach) and -`declared`. Their sources import the core as `../../src/plugins/api.ts`, the +`plugins/`. + +For a language Coherence lacks, start from `python`: it reads its +text through a tree-sitter parser and queries (below, reading through a +parser), the one way a plugin reads its language's text, so the readings +come from one parse and none can disagree with another or miss a statement +that spans lines. Every bundled language plugin reads this way: `go` (a package as a module, +its qualified uses), `rust` (paths spelled in pieces), `typescript` +(default exports; the TSX grammar, with the TypeScript grammar as its +alternate, both patched). They are +also the examples of an adapter over a language server: `go` drives gopls, +`rust` a server with no npm package. `declared` completes the set. Their sources import the core as `../../src/plugins/api.ts`, the same module the package exports as `@posthog/coherence/plugin`; an ejected copy names it the second way, and so should a plugin you write. @@ -126,11 +135,12 @@ copy names it the second way, and so should a plugin you write. { "name": "sample", "version": "0.1.0", - "pluginApi": 2, + "pluginApi": 4, "provides": { "language": "swift" }, "extensions": [".swift"], "testFolders": ["Tests"], "module": "./index.ts", + "treeSitter": { "parser": "tree-sitter-swift.wasm", "queries": "swift.scm", "resolve": "swift-resolve.ts#SWIFT_RESOLVE" }, "ladder": { "top": "reference-choked", "because": "...", "rungs": [] }, "verifiers": [ { "form": "sample prove", "evidence": "model-checked" }, @@ -143,20 +153,23 @@ copy names it the second way, and so should a plugin you write. | Key | Meaning | |---|---| | `name`, `version` | Who the plugin is. Every run entry its adapter or verifier answers names both. | -| `pluginApi` | The interface version it was written for. This release runs `2` and reads plugins written for `1` to `2`: a plugin written for `1` loads, and the session start names it with what changed since. Any other version is refused, naming both. | -| `provides.language` | The language its adapter answers for. A built-in name takes the built-in's place (see the swap rule). A new name needs `extensions` (or `files`), and the config's `language` must name it; the language is then read as a bundled one is, for that project: its files, test files and folders, its entrance rules, its CI steps and every syntax slot it fills. | +| `pluginApi` | The interface version it was written for. This release runs `4` and reads plugins written for `1` to `4`: a plugin written for an older one loads, and the session start names it with what changed since. Any other version is refused, naming both. Version 4 removed the hand-written reader slots (`source`, `declares`, `topLevel` and `kept` under `syntax`): a language's declarations, imports and exports are read through `treeSitter` alone, a manifest that fills one is refused naming each, whatever version it is written for, and the `interfaces` table states `serverBounds` alone (below, the syntax slots). Version 3 brought the parser path (`treeSitter`), imports that resolve to a module of several files, the adapter's `topLevelSymbols`, and `check.json`'s `reference` map; `plugin check` holds a plugin to the reference reading and server agrees duties from 3, and tells a plugin written for 2 they are not held. | +| `provides` | `language`: the language its adapter answers for (or `declaredLanguages: true`, the bundled declared plugin's, for the languages a config declares). A built-in name takes the built-in's place (see the swap rule). A new name needs `extensions` (or `files`), and the config's `language` must name it; the language is then read as a bundled one is, for that project: its files, test files and folders, its entrance rules, its CI steps, its parser and every syntax slot it fills. | | `extends` | The language whose adapter it is handed to wrap, as `base` (Convex extends `typescript`). A plugin for a language of its own extends nothing. | | `extensions` | The files a new language is written in. An extension a built-in, a declared language, or another plugin owns is refused. | | `module` | The module, relative to the manifest. Required for an adapter, and for a verifier with no `command`. | | `ladder` | The rungs the adapter grades on: `top`, `because`, `rungs`, and optionally `whenVacuous`, the rung a chokepoint stands on when the refutation could not see its staged uses (absent, the earned rung stands with the verdict not run). Absent, the wrapped adapter's; with none, reference-choked alone, enforced by Coherence's check. | | `verifiers` | The via forms it proves (below). A `command` must name `{name}`; a command that is never told what to prove is refused. An optional `match` is a regular expression its output must match for an exit 0 to pass. | | `lexicon` | Its lexicon layer, relative to the manifest. | -| `syntax` | The syntax slots it fills, each `"#"` (below). | +| `syntax` | The syntax slots it fills, each `"#"` (below). No slot answers a reading of the language's declarations, imports or exports, which are the parser's: a manifest that names `source`, `declares`, `topLevel` or `kept` is refused, and so is an `interfaces` table that answers anything but `serverBounds`. | +| `treeSitter` | The tree-sitter parser its language's text is read through, and the queries over it (below, reading through a parser): the one way a plugin reads its language's text. The core derives from the parse every reading of the language's declarations, imports and exports: the names a file declares, what each declares, its imports, its type declarations, default exports, renamed imports and wildcard imports; a language whose plugin names none is not read. | | `files` | The files a language is written in, as a regular expression `pattern` with an optional `except` (TypeScript, as JSON writes them: `\\.(?:[cm]?[tj]sx?)$` except `\\.d\\.ts$`); `extensions` is the short form for a plain list. | | `source` | `except`: of the language's files, those the plain source scan leaves out (TypeScript's JavaScript, Python's stubs). | | `serverExtensions` | The extensions the language server can report a site in or resolve a name to. | | `testFiles` | Regular expressions a test file's base name matches by the language's own naming (pytest's `^test_.*\\.py$`), beside `.test.`/`.spec.` and the test folders. | | `testFolders` | Folder names whose files are all tests by the language's own layout, wherever they sit (SwiftPM's `Tests`), beside the config's test folders. A name matches a folder exactly, case and all. | +| `basisFiles` | Regular expressions a base name matches for the files besides source the language's answers and entrances rest on: its configuration, manifests and lockfiles (`^Cargo\\.toml$`). A kept answer and the Structure reading's fingerprint are read against them. | +| `moduleFolders` | Regular expressions a module file's path matches, the first group the folder it owns (`^(.*)/__init__\\.py$`), by which a chokepoint that is a module covers its folder's files. | | `members` | How an exported type's body reads for the lexicon's member scan: `opens`, `closes`, `field`, each a regular expression. | | `entrances` | The entrance detection rules (`rule`, `plural`, `detects`) and `notDetected`, what they miss: printed by the query, the page and orient. | | `notScanned` | Why the text scans do not read the language. Present, it turns off every reading that scans the language's text, whatever slots are filled: mass, entrance detection and the Structure reading each name the language as not read, with this reason. No bundled plugin carries it, and `plugin check` fails a plugin that does: every language plugin owes the readings of its text (the reading duties below), and none is waived. It stays so that a plugin still being written says what it does not read rather than measuring as a project of no code. | @@ -220,20 +233,39 @@ there is not, so the copy never makes the name ambiguous. ### The syntax slots -The readings scan a language by the tables its plugin's manifest names under -`syntax`, each as `"#"`, loaded synchronously, once, when a -reading first asks for that slot: +A language plugin reads its text through a parser (below, reading through +a parser), from which the core derives every reading of the language's +declarations, imports and exports: the names a file declares and whether it +exports each (the economy and mass), what each declares (the observation's +interface map), what a file's top level declares (the spec model's check +that a handler, guard or mirror exists), its imports, and the Structure +reading's type declarations, default exports, renamed imports and wildcard +imports (the kept answers read the last). No slot answers one of those: +the hand-written reader slots of pluginApi 3 and before (`source`, +`declares`, `topLevel`, `kept`) are gone, and a manifest that names one is +refused, whatever `pluginApi` it is written for; and an `interfaces` table +that answers `importLists`, `wildcardModules`, `isTypeDeclaration`, +`isDefaultExport`, `defaultNames` or anything but `serverBounds` is refused +naming each, whether or not its plugin names a parser. + +The plugin fills the slots no parse answers. Two of them still read a +file's text by hand, for what the parse does not derive: `entrances` reads a +code file for a framework's entrance rules (`candidates`), the lines a +statement spans (`definitionAt`, `continues`), whether the file binds a name +a call spells (`binds`) and, for TypeScript, which code files another imports +by a relative path (`importedAmong`); `lists` reads the literal a list is set +to. The others read no text of the language: `notice` a line for the session +start, `boundaries` a tool's declaration file (tach's), and `interfaces` the +language's facts. The tables are named under `syntax`, each as +`"#"`, loaded synchronously, once, when a reading first asks +for that slot: | Slot | Read by | Type | |---|---|---| | `entrances` | entrance detection | `EntranceSyntax` | -| `interfaces` | the Structure reading | `InterfaceSyntax` | -| `kept` | the Structure reading's kept answers, when filled; else `interfaces.wildcardModules` | `(file, text) => string[]` | -| `source` | the economy and mass | `SourceSyntax` | -| `declares` | the observation's interface map | `(line) => "type" \| "value" \| "body" \| "unknown"` | +| `interfaces` | the Structure reading: whether the language's server narrows to bounds | `InterfaceFacts`: `{ serverBounds }` alone | | `notice` | the session start | `(root) => string` | -| `lists` | declared mirrors | `(text, name) => Literal \| undefined` | -| `topLevel` | the spec model's check that a handler, guard or mirror is declared | `(text, name) => boolean` | +| `lists` | declared mirrors, for a list in the language's files; a file of a language whose plugin fills none is read as TypeScript | `(text, name) => Literal \| undefined` | | `boundaries` | `scaffold import` and adoption | `BoundarySource`: a tool's declaration file read into modules, as tach's | An `EntranceSyntax`'s `manifestCandidates(read, exists, files)` is handed the @@ -243,13 +275,14 @@ A candidate may carry a `name`, the one `scaffold entrances` proposes when the plugin knows a better one than its symbol gives (a Rust binary by the name its Cargo.toml gives it), so no language's layout is known in the core. -Every type is exported from `@posthog/coherence/plugin`. A slot a plugin leaves empty reads as "not read for ", never as -another language: a plugin that fills no `source` slot is named not read by -mass and every reading that scans text, and one that fills no `interfaces` -slot by the Structure reading. The kept answers read the `interfaces` slot's -`wildcardModules`; the `kept` slot is still read when a plugin fills it, and -`plugin check` fails a plugin whose two slots answer with one function or -two spelled alike (its "one answer each" duty). +Every type is exported from `@posthog/coherence/plugin`. A language read +without a parser, or a slot a plugin leaves empty, reads as "not read for +", never as another language: a plugin that names no parser is +named not read by mass, the Structure reading and every reading that scans +text, and one that fills no `interfaces` table reads as a server that takes +no bounds. `plugin check` fails a +plugin whose two slots answer with one function or two spelled alike (its +"one answer each" duty). Two manifest fields name a language's files so the core never does: `basisFiles`, regular expressions a base name matches for the files besides @@ -266,6 +299,269 @@ an enhancement of the adapter alone keeps every reading of the language. Its file rule is one rule: a plugin that names its files, by `files` or `extensions`, owns them whole. +### Reading through a parser + +A plugin that provides a language can hand Coherence a +[tree-sitter](https://tree-sitter.github.io/) parser for it, and queries +over its syntax tree, in place of hand-written readers. Coherence parses +each file once per reading and derives every reading of its text from the +same parse: the names a file declares at its top level, what each declares, +and every import. A statement is read whole, whatever lines it spans; text +inside a string or a comment is never read as code. Every bundled +language plugin reads this way (`plugins/python`, `plugins/go`, +`plugins/rust`, `plugins/typescript`). + +```json +"treeSitter": { + "parser": "tree-sitter-python.wasm", + "queries": "python.scm", + "resolve": "python-source.ts#PYTHON_RESOLVE", + "privateName": "^_" +} +``` + +| Key | Meaning | +|---|---| +| `parser` | The language's parser compiled to WebAssembly, beside the manifest. Many grammars' npm packages ship one (`tree-sitter-python`, `tree-sitter-rust`, `tree-sitter-go`, `tree-sitter-java`, `tree-sitter-c`): copy the `.wasm` out of the package. For a grammar whose npm package ships none, look on the grammar's GitHub releases first: `tree-sitter-swift` attaches `tree-sitter-swift.wasm` to each release. Failing that, run `tree-sitter build --wasm` in the grammar's repository; the tree-sitter CLI (0.27) compiles it with wasi-sdk's clang and optimizes it with binaryen's wasm-opt, each downloaded on first use, or the copies `TREE_SITTER_WASI_SDK_PATH` and `TREE_SITTER_BINARYEN_PATH` name. Coherence runs web-tree-sitter 0.27, which loads parsers built for language ABI 13 to 15. | +| `alternate` | Optional: a second parser of the same language, beside the manifest, read with the same queries where the `parser`'s tree holds an error and its own errors cover less of the text (TypeScript's TypeScript grammar beside its TSX grammar). It is compiled the first time a text needs it, and queries that do not compile against it are refused then. | +| `queries` | A file of tree-sitter queries, beside the manifest, whose captures are the names below. A query that does not compile against the parser, or a capture Coherence reads nothing by, is refused naming the plugin. | +| `resolve` | `"#"`: a `ModuleResolution`, `{ resolveModule(root, from, specifier, vanished), modulePaths(from, specifier), boundName?(specifier) }`. Where an import leads is the language's rule, not its syntax, so it stays code: `resolveModule` names the project file a specifier leads to, or, where the language's module is several files (a Go package, a SwiftPM target), the module as `{ module: "", files: [""] }`, or `undefined` outside the project. `modulePaths` gives every spelling of the files a glob import names. `boundName`, optional, gives the name a whole-module import binds when it gives none (a Go package's name, from its path); absent, the specifier's last path element. | +| `privateName` | For a language that exports by name rather than by a keyword: a regular expression a name it keeps private matches (Python's `^_`, Go's `^\\P{Lu}`), read with Unicode's character classes (the `u` flag). A language that exports by keyword captures `@exported` instead. | +| `separator` | For queries that capture `@import.prefix`: the text the language joins a path's segments with (Rust's `::`), which joins each prefix to the path it prefixes. | + +The captures: + +| Capture | On | Means | +|---|---|---| +| `@import` | an import's whole statement, in the same match as its other captures | the statement: `coherence plugin shapes` reads from it whether the import spans lines or sits inside a block | +| `@import.from` | the module node of an import that names what it brings in | the specifier, as written (`..pkg.mod`) | +| `@import.name` | each name it brings in, one match per name | the name | +| `@import.alias` | the name it is bound to, when renamed | the alias | +| `@import.glob` | the glob (`*`) | every name the module exports | +| `@import.module` | the module of a whole-module import (`import os.path`) | the specifier | +| `@import.prefix` | a path a group spells in pieces (Rust's `use a::b::{c, d}`: the `a::b`) | joined by `separator` to each specifier inside it, so `a::b::c` is read whole | +| `@import.default` | the name a default import binds (TypeScript's `import foo from "./m"`) | the module's default export, under that name | +| `@declaration.body`, `@declaration.value`, `@declaration.type`, `@declaration.unknown` | a top-level declaration, by what it declares | the declaration; its line is its `@name`'s | +| `@name` | the declaration's name | the name | +| `@bound` | a top-level name the file binds without declaring it (Python's lowercase module variables) | the spec model's check that a handler, guard or mirror exists reads it; mass does not | +| `@exported` | anything in a declaration's match | the file exports it | +| `@default` | anything in a declaration's match, or a name alone (`export default foo`) | the file exports it, or that name, as its default | +| `@use.qualifier`, `@use.name` | a use through a whole-module import (Go's `st.Seal`) | the file uses that name of the module it binds as the qualifier, so the import joins only the file that declares it | +| `@misread` | a node valid source never holds (TypeScript's reserved words read as a name) | the parser misread the text: in a tree with no error, orient says so with the word and its line | + +A capture whose name starts with an underscore (`@_alias`) is the queries' +own, for a predicate to test (`(#eq? @_alias "default")`); Coherence reads +nothing by it and never refuses it. + +Beside tree-sitter's own predicates (`#match?`, `#eq?`, `#any-of?` and their +negations), Coherence evaluates `#not-parent-type? @capture type...`, which +holds where the captured node's parent is none of those types: the +TypeScript plugin exempts an import's or an export's name, where a reserved +word is valid (`export { x as default }`), from `@misread`. Any other +predicate is refused by name, since nothing would evaluate it. + +An import that resolves to a module joins, of the module's files, those +that declare the name it imports (read through the plugin's own parser), and +every file of the module when it imports the module whole or no file declares +the name. Return the module and let Coherence choose: a plugin that picks one +file of a module (its first, the one named after it) misses the importer's +other files, and two plugins that pick differently read one project two ways. +The bundled Go plugin returns a package this way. + +Python's queries (`plugins/python/python.scm`) are the worked example: +one pattern per shape of import, then one per kind of declaration, each +anchored to the module so a nested definition is no top-level one. Go's +(`go.scm`) add qualified uses, Rust's (`rust.scm`) prefixes, TypeScript's +(`typescript.scm`) default exports and the queries' own captures. + +A grammar reads the language as its release knew it, and text it cannot +read is an error in the tree. Where the error lands is the grammar's +recovery, not a rule: it may hold one expression, or swallow every +declaration after it into the one before, so a reading can lose names past +it without saying so. `coherence plugin calibrate` counts what the reading +and the language server disagree on, so a project can see what its grammar +misses. The bundled Go grammar (0.25) predates Go 1.26. + +When a grammar's release cannot read code a project writes, a plugin may +carry its own build of it. The TypeScript plugin's two grammars are +tree-sitter-typescript 0.23.2 with a patch, since upstream has merged no +grammar change since that release: they read an import type with type +arguments or as an array's element (`import('x').T`, `import('x').T[]`), +a member named `in` or `instanceof` (`in?: T`, `in = 2`, `in?(): void`) or +beginning with `in` and a digit, `_`, `$` or `\` (`in_progress`, `in$`, +`in2(): T`), and a statement beginning so (`in_flight()`), on the line +after another, and a bare `&` in JSX text or a JSX string, each of which hid +the declarations after it in PostHog's frontend. The patch and the scripts +that rebuild both parsers byte for byte are in `grammars/tree-sitter-typescript` +in Coherence's repository. The build runs in two phases. The fetch phase +downloads every input and checks it by the digest `inputs.sha256` records (the +CLI, clang and wasm-opt the parsers are compiled with, tree-sitter-javascript, +and the TypeScript and web-tree-sitter packages the comparison reads with), +and clones the upstream grammar at its pinned commit. The build phase runs +with the network denied by what runs it: `sandbox-exec` on macOS, docker with +`--network none` on Linux and in CI (`unshare -rn` where there is no docker, +which leaves the machine's unix sockets reachable). Its own attempt to +connect is a tripwire for a phase started with the network on, not the +denial. It checks every input again and builds from the upstream commit's +tree, hashed again and held to the tree `inputs.sh` pins, so no ref or replace +object in the clone has a say. The patch may change the grammar and its +scanner (`common/define-grammar.js`, `common/scanner.h`) and nothing else; one +that touches another file is refused, and the patched grammar is the clean +tree with those two files alone taken from it. The phase then runs +upstream's test corpus, read from the clean tree, and Coherence's, kept in +`corpus/` outside the patch so the patch cannot rewrite what it is held to, +each case with its whole expected tree, in both dialects; builds the stock +parsers beside the patched ones; and compares what the two read, node by +node, over that corpus, TypeScript's own lib declaration files and +Coherence's source. Any difference `intended-differences.json` does not name +by its construct fails the build, as does any token the patched parsers read +as another type than the stock ones do, any expected tree the bundled +parsers do not read, any intended difference that does not show as the +one region of each case it names, one form to a case, and any difference at +all in a corpus case no entry names, whatever an entry's query overlaps; the +list names six fixes and one regression, below. That holds over those inputs alone: a form +none of them holds can read differently with no check failing (a scanner +that also took `in (` as a member's name read `key\n in (record)` as a call +of a function named `in`, and passed every check). Where the misread leaves +a reserved word as a name, the plugin's `@misread` query catches it in +whatever file Coherence reads, and orient says so. The patch's files cannot +change the corpus, but its code runs in the build (`define-grammar.js` under +node when the grammar is generated, `scanner.h` compiled into the corpus +run), with the build's working folder open to it; nothing checks what it +does there. The build phase writes the bundled parsers +only once each is the digest `parsers.sha256` records. CI runs it on every +pull request in a container with no network, and fails its checks unless +every difference is listed and both parsers come out as the ones bundled. Still +errors, as with the stock grammar, each a case in `corpus/limits.txt` that +must read exactly as the stock parsers read it: an optional destructured parameter in a +function type (`({ a }?: T) => U`), a parenthesized import type, `typeof +import('x')` as a call's type argument (`importOriginal()`), a method named `in` (`in() {}`) after another member, and variance +annotations (``). A comparison after an import type +(`x as import('x').T < y`) now errs too, as it does after any other type +(`x as T < y`) and as TypeScript's own compiler refuses it. Around a +parenthesized import type, which errs with the stock grammar too, the +patched grammar can recover less: where it reads such a file as one error +at its root, none of the file's declarations are read, those before the +import type included. Over about 106,000 files of TypeScript from +node_modules, mostly type declarations, 4 files read 11 declarations fewer +than with the stock grammar (8 more read none of the declaration named +import the stock grammar's error made up); over PostHog's 21,159 TypeScript +files, none. + +A language with two grammars names the second as its `alternate`: a text +whose tree from `parser` holds an error is parsed again with it, and the +tree whose errors cover less of the text is read (one error that swallows +the rest of a file loses more than two that hold a token each), through +the same queries, which must compile against both; the alternate is +compiled the first time a text needs it. TypeScript reads every `.ts`, `.tsx` and `.js` file +with the TSX grammar, since it reads JSX, and names the TypeScript grammar +as its alternate: to TSX an old-style cast (`value`) opens a JSX tag +that swallows the rest of the file, and the TypeScript grammar reads it as +a cast. Its queries name no JSX node, which the TypeScript grammar lacks, so +a constant whose value is JSX declares `unknown`. + +The plugin still fills the slots no parse answers: `entrances` (a +framework's rules), `notice`, `lists`, `boundaries`, and an `interfaces` +table for the language's one fact (whether its server narrows to bounds). +A manifest that fills `source`, `declares`, `topLevel` or `kept`, the +hand-written readers pluginApi 4 removed, is refused in one problem naming +each, whatever version it is written for and whether or not it names a +parser; to move one, write the queries that capture what it read, and the +core derives the reading from them. An `interfaces` table that answers +anything but `serverBounds` (`importLists`, `wildcardModules`, +`isTypeDeclaration`, `isDefaultExport`, `defaultNames`, which pluginApi 3's +tables answered) is refused naming each when it is first loaded, whether or +not its plugin names a parser, and `plugin check`'s "one answer each" duty +fails on it: the core reads those through the parse alone, so a table's own +could never be read. A second reader of the same text is how two readings +of it come to disagree, as Python's two hand-written readers of its imports +did. + +Parsing costs: a WebAssembly parser reads about 11 MB of text a second, so +Coherence keeps each text's parse in the user's own cache +(`$XDG_CACHE_HOME/coherence/parses`, else `~/.cache/coherence/parses`), +filed by the parser's fingerprint and the text's digest, never in a +project. The warm-up a session start launches parses every source file once +in the background; after that a reading of the whole project, or of any +project or worktree holding the same text, parses only the texts that +changed (PostHog's 19,902 Python files: 32 s for the first warm-up, 2 s for +the next, and mass in 3.4 s, measured 2026-10-27). Each parse is a file of +its own, named by the text's digest, written whole under a temporary name +and renamed into place, as git keeps a loose object, and never written +again; a reading opens only the files of the texts it reads and holds no +store in memory. Two warm-ups at once need no lock, since neither can spoil +what the other writes. A kept parse is stamped as read at most once a day, +and a warm-up removes, once a day, every kept parse no process has read in +fourteen days. +The fingerprint digests everything a kept parse depends on: the parser and +its `alternate`, the queries, the `separator`, the web-tree-sitter release +and the Coherence code that reads a tree. Changing any of them changes the +fingerprint, so nothing kept under the old ones is read; `privateName` and +`resolve` are read after the store and change no kept parse. Each warm-up +also parses a sample of the texts it found kept and compares; a store that +differs from a fresh parse is removed, and the next session start says so. +The store is used only where no one but the user and the system can change +what its path leads to: every folder and link on the way owned by the user +or the system, none others may write unless it is sticky (the system's +temporary folder), and the store's own folders the user's alone; each kept +parse is read only where it is the user's own regular file, no link, that no +one else may write. A folder only the user's own personal group may write +(the user's primary group, named as the user, with no other member, as +Debian and Ubuntu make one) counts as the user's; access lists (macOS ACLs) +are not read. A store inside the repository being read, as a cache set +inside a checkout puts it, is not used for that repository. Elsewhere every +text is parsed, and orient says the store is off and why. The warm-up reads +only a project's regular source files whose real path is inside the project, +never one through a link or larger than 16 MB, and a file nested thousands +deep around an error is read like any other. Each parse and query of a text +stops past a fixed amount of work, counted in the parser's own progress +calls, the same on every machine: a text past it (a generated file of +millions of one-line statements; PostHog's largest source file uses a tenth +of the bound) reads as declaring and importing nothing, is kept nowhere, and +orient names it. +`plugin eject` copies a plugin's parser byte for byte with its queries, so +an ejected copy reads as the bundled plugin read. + +Every language plugin's `check.json` maps its files and names onto one +reference project, the same in every language, under `reference`: +`files` names the file playing each role (`secrets`, declaring +`SECRET_COLUMNS` and `seal`; `rows`, declaring `Row`, in the same module as +`secrets`; `render`, using all three; `main`, using `render`), and `names` +the language's spelling of each of `SECRET_COLUMNS`, `seal`, `Row` and +`render`. The reference reading duty holds the plugin to recover each +relation over it, and `coherence plugin compare` lays every language +plugin's reading of it side by side, the bundled ones and the project's, +naming each that reads a relation another way (exit 1). A store of two files +is the point: a plugin that resolves an import of a module to one file of it +misses the other here. + +`coherence plugin calibrate [--files ]`, run in a project, holds each +language's text reading to its language server over the first n source +files: the declarations the server reports too, each it does not (a misread, +with its file and line), and what the server reports that the reading leaves +out, counted by symbol kind. An adapter takes part by offering +`topLevelSymbols(file)`, the server's top-level symbols with their lines and +LSP kinds; the bundled adapters do, and from pluginApi 3 every adapter over +a language server must. + +`coherence plugin shapes`, run in a project, counts each shape of import +its code writes (named, renamed, glob, whole module, spans lines, inside a +block) through each language's parser, beside how many of each the plugin's +check projects put to it (an import there counts only when it resolves to a +file of the check project, since only those are what the imports duty +compares; the check projects are the ones plugin check reads, found by +language), and names each shape the project writes that no check project +puts to the plugin as untested: plugin check never puts that shape to the +plugin, so a reader could miss every one and pass. Add one to the plugin's +`check.json` files and `readings.imports`. Capture each import's whole +statement as `@import` so the census can tell an import inside a block. + +The parser runtime starts once per process, before any command. Code that +imports Coherence's modules and asks a reading itself, outside its CLI, +first awaits `startParsers()` (`@posthog/coherence/dist/plugins/syntax-trees.js`); +a reading asked before then is refused saying so. + ## Writing a language adapter An adapter answers the questions a chokepoint check asks, about one language, @@ -287,6 +583,7 @@ reader's side; this is the author's side. | `forget(files?)` | Make the instrument read the disk again: the named files, or all it may have open. Resolve only once the instrument has taken the change in, since the edit hook checks again right after. | | `close()` | Stop what the adapter started. The core closes a `base` it handed you. | | `serverPid()` | Optional: the server's process id, so a reading can bound its memory. | +| `topLevelSymbols(file)` | Required from pluginApi 3 for an adapter over a language server: the symbols the server reports a file declaring at its top level, each `{ name, line, kind }` (one-based line, LSP SymbolKind), from `textDocument/documentSymbol`'s top level (a flat answer's symbols with a container left out). `plugin check`'s server agrees duty and `coherence plugin calibrate` hold the text readings to it. An adapter that extends a language may leave it to the one it wraps. | ### The refutation @@ -381,22 +678,25 @@ one wanting changes a copy of it: | Duty | Holds when | |---|---| | file rule | the files `check.json` names as the language's are, and the others are not | - | declarations | the `topLevel` slot says which names a file declares, as `check.json` says | + | declarations | the parser's top-level reading says which names a file declares, as `check.json` says | + | reference reading | the readings recover, over the check project, every relation of the reference project its `reference` map places there (below); held from pluginApi 3 | | references | the adapter reports every reference to the protected thing, and none else; one that reports none fails here, by name | + | server agrees | every name the text reading finds a file declaring is a top-level symbol the language server reports for that file (the adapter's `topLevelSymbols`, required from pluginApi 3; a plugin written for 2 is told it is not held) | | chokepoint | the run grades the chokepoint as `check.json` expects, bypasses named, its refutation seen or refused | - | mass | mass reads the language, counts each file, and the `source` slot's scan finds in each the names `check.json`'s `readings.declared` gives | - | imports | the `source` slot's scan reads every import `readings.imports` names, resolved to its project file, and none else: what the economy's closure walks | + | mass | mass reads the language, counts each file, and the parser's scan finds in each the names `check.json`'s `readings.declared` gives | + | imports | the parser's scan reads every import `readings.imports` names, resolved to its project file, and none else: what the economy's closure walks | | interfaces | with each folder `readings.interfaces` names a component, the component interface reading finds the symbols one uses of another, and none else | | entrances | entrance detection finds every entrance `readings.entrances` names, by file, handler and rule, and none else | + | answers agree | where two readings answer one question of the same text, they agree over every file: a name the scan declares is one the top-level reading finds; a type declaration where the interfaces reading of its line alone and the declares reading of the whole text both say so (queries that read a declaration by what surrounds it fail here); a name an import list renames is one the scan reads imported | | one answer each | no two of its slots answer with one function, or two spelled alike | Each duty passes, fails with why, or is not run with why (the language server is absent). The command exits 0 only when every one passes. The reading duties run each reading as a project's runs, through - the core, so a slot that answers in its type and reads nothing (a - `declarationOf` that always says `undefined`) fails every reading it - feeds, by what each missed, and so does a slot left empty: a slot's - success is what the readings that consume it recover. No plugin waives a + the core, so queries that capture nothing fail every reading they feed, + by what each missed, and so does a language read without a parser or a + slot left empty: a reading's success is what the readings that consume + it recover. No plugin waives a reading; a check project that names no `readings` fails each reading duty as nothing to check. The bundled plugin's `check.json` for the language, as the installed package ships it, is the minimum: every plugin for that @@ -416,12 +716,12 @@ one wanting changes a copy of it: |---|---| | `files` | The project: each file's text by its path from the root. The check writes them into a scratch folder, with a config that runs the plugin, and reads nothing else. | | `language` | `{ "files": [...], "not": [...] }`: paths the file rule must take as the language's, and paths it must not. Only the names are read, so a path need not be in `files`. | - | `declarations` | `[{ "file", "name", "declared" }]`: what the `topLevel` slot must say of a name in one of `files`. | + | `declarations` | `[{ "file", "name", "declared" }]`: what the parser's top-level reading must say of a name in one of `files`. | | `protects`, `chokepoint` | The thing and its one way in, written as a spec bullet writes them (`Seal`, `Name in file.go`). | | `references` | Every reference to `protects` as `file:line`, the line 1-based, test files' included: the adapter must report exactly these, none missed and none more. | | `grade` | What the run grades the chokepoint (`broken`, `reference-choked`, `visibility-choked`). | | `bypasses` | The references outside the chokepoint the run must name, as `file:line`; a test file's never is one. | - | `readings` | What each reading of the language's text must recover over `files`, each compared exactly, each with at least one answer: `declared`, `{ "": ["Name", ...] }` for every non-test file of the language; `imports`, `[{ "file", "module", "names" }]`, one per file and the project file it imports from, `"*"` for the module whole; `interfaces`, `[{ "from", "to", "symbols" }]`, component folders and the symbols of `to` that `from` uses; `entrances`, `[{ "file", "symbol", "rule" }]`, `symbol` empty when the file itself is the entrance. Write it for your small project before you write a slot: it is the slot's spec. | + | `readings` | What each reading of the language's text must recover over `files`, each compared exactly, each with at least one answer: `declared`, `{ "": ["Name", ...] }` for every non-test file of the language; `imports`, `[{ "file", "module", "names" }]`, one per file and the project file it imports from, `"*"` for the module whole; `interfaces`, `[{ "from", "to", "symbols" }]`, component folders and the symbols of `to` that `from` uses; `entrances`, `[{ "file", "symbol", "rule" }]`, `symbol` empty when the file itself is the entrance. Write it for your small project before you write the queries: it is their spec. | 4. **Swap back**: remove the `plugins` entry, and the bundled plugin answers again. @@ -432,7 +732,22 @@ the module's `syntax` export into `plugin.json` (`"syntax": { "": "#" }`), made the member scan `plugin.json` data (`members`), and added the `kept`, `declares`, `notice`, `topLevel` and `boundaries` slots. A module that still exports `syntax` is -refused at load, by name, rather than read as having none. +refused at load, by name, rather than read as having none. `pluginApi` 4 +removed the hand-written reader slots (`source`, `declares`, `topLevel`, +`kept`): a manifest that fills one is refused, whatever version it is +written for, in one problem naming each. Every bundled language plugin of +Coherence 1.10 and before filled `source`, `declares` and `topLevel` by +hand, so a copy `plugin eject` made then is refused, and so is a plugin +written from that release's guide. The refusal names the simplest recovery +first: a plugin named as a bundled one is said to be ejected from an older +Coherence, and is ejected again from this version (set its entry in the +config back to `"bundled"`, run `coherence plugin eject --to `) with its changes reapplied to the new copy; a plugin written from +scratch reads its language through `treeSitter`, a grammar's `.wasm` and +queries (above, reading through a parser). Version 4 also left the +`interfaces` table its one fact, `serverBounds`. A plugin of 1 to 3 that +fills none of the removed slots, and whose `interfaces` table states +nothing else, still loads. ## Roles @@ -540,8 +855,10 @@ it) reads a Go module through gopls: test code. - **Read by the readings.** Go's files, tests and `vendor` folder, and its top-level declarations, so the spec check reads an entrance's handler or - a guard in a Go file. Not yet: entrance detection (declare each under - `## entrances`) and the text scans mass and the economy read by. + a guard in a Go file; its entrances (a `main` package's `main`, an HTTP + handler it registers); and its imports through its parser: a package is + one module of its files, and a use through the package (`st.Seal`) joins + the file that declares the name. - **gopls** is found from `COHERENCE_GOPLS`, else the `PATH`, else `go env GOPATH`/bin; with none, every Go chokepoint reads not run with how to install it. `ci install` sets up Go and gopls in the workflow it diff --git a/grammars/tree-sitter-typescript/build-phase.sh b/grammars/tree-sitter-typescript/build-phase.sh new file mode 100755 index 00000000..33c22d20 --- /dev/null +++ b/grammars/tree-sitter-typescript/build-phase.sh @@ -0,0 +1,153 @@ +#!/bin/sh +# The build phase: builds both parsers from the inputs fetch.sh fetched, compares them with the stock ones, and writes +# the bundled parsers to the folder given only once every check passes. It is meant to run with the network denied: +# build.sh runs it under sandbox-exec on macOS and in docker with --network none on Linux, CI in docker with +# --network none. That denial is the sandbox's or the container's, never this script's: the connection attempt below is +# a tripwire, which catches a build phase started with the network on by mistake, and which a process that wants the +# network can fool (a stubbed net module, a daemon reached over a socket). +# 1. Every file in the inputs folder is one inputs.sha256 lists, at its digest. The upstream grammar is the tree of its +# pinned commit, read with replace objects ignored, and the files extracted from it are hashed again here and must +# be the tree inputs.sh pins, so no ref, replace object or graft in the clone has a say in what is built. +# 2. coherence.patch is applied to a copy of that tree, and refused unless all it changes is common/define-grammar.js +# and common/scanner.h, each a regular file still. The patched grammar is the clean tree with those two files alone +# taken from it, so no file of a patch's is the corpus, upstream's or Coherence's. The patch's code still runs here: +# define-grammar.js under node when the grammar is generated, scanner.h compiled into the corpus run, each with this +# phase's working folder open to it, and nothing checks what it does there. +# 3. The stock grammar (upstream, unpatched) and the patched one are each generated and built, in both dialects, with +# the pinned tree-sitter CLI, wasi-sdk clang and binaryen wasm-opt. +# 4. Upstream's corpus, read from the clean tree, and Coherence's (corpus/coherence*.txt, in this folder, which the +# patch cannot write) pass against the patched grammar in both dialects, each case with its whole expected tree. +# 5. compare.mjs parses upstream's corpus, Coherence's, corpus/limits.txt, TypeScript 5.9.3's lib .d.ts files and this +# repository's src and mods with the stock and the patched parsers, fails on any difference intended-differences.json +# does not allow, holds every intended difference to each case it names, one region in each, fails on any region +# in a corpus case no entry names (limits.txt's forms among them), whatever an entry's query overlaps, and holds the +# patched parsers to every expected tree the corpus declares. +# 6. Each patched parser is byte for byte the digest parsers.sha256 records. +# Needs node, git, tar, gzip and a C compiler (the corpus runs natively); the CLI's binaries need macOS, or Linux with +# glibc 2.39 or newer, arm64 or x86-64. +set -eu +here=$(cd "$(dirname "$0")" && pwd) +repo=$(cd "$here/../.." && pwd) +. "$here/inputs.sh" +[ $# -eq 2 ] || { echo "usage: build-phase.sh " >&2; exit 2; } +inputs=$(cd "$1" && pwd) +out=$2 + +# A tripwire, not the denial: a connection to any of these, by name or by address, stops a build phase started with the +# network on by mistake before it reads an input. It cannot prove the network is denied (a stubbed net module answers +# it as a denied one would); the sandbox or the container that runs this phase is what denies it. +node -e ' + const net = require("node:net"); + const hosts = ["github.com", "registry.npmjs.org", "objects.githubusercontent.com", "1.1.1.1", "8.8.8.8", "140.82.112.3"]; + Promise.all(hosts.map((host) => new Promise((done) => { + const socket = net.connect({ host, port: 443, timeout: 5000 }); + socket.on("connect", () => { socket.destroy(); done(host); }); + socket.on("timeout", () => { socket.destroy(); done(null); }); + socket.on("error", () => done(null)); + }))).then((reached) => { + const open = reached.filter((host) => host !== null); + if (open.length > 0) { console.error(`build-phase.sh: reached ${open.join(", ")}; run the build phase where the network is denied (build.sh does)`); process.exit(1); } + }); +' + +# The inputs, each at its digest, and nothing else beside them. +for path in "$inputs"/* "$inputs"/.[!.]*; do + [ -e "$path" ] || continue + file=$(basename "$path") + [ "$file" = tree-sitter-typescript ] && continue + want=$(digest_in "$here/inputs.sha256" "$file") + [ -n "$want" ] || { echo "build-phase.sh: $file is no input inputs.sha256 lists" >&2; exit 1; } + got=$(sha256 "$path") + [ "$got" = "$want" ] || { echo "build-phase.sh: $file is $got, not $want" >&2; exit 1; } +done +for file in $input_files; do [ -f "$inputs/$file" ] || { echo "build-phase.sh: no $file in $inputs" >&2; exit 1; }; done + +work=$(mktemp -d) +# The clean tree is made read-only below, so it is made writable again to be removed. +trap 'chmod -R u+w "${work:?}" 2>/dev/null; rm -rf "${work:?}"' EXIT +# git with no configuration but its own, and no repository but the one given: no global attributes, filters or hooks. +export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null GIT_CEILING_DIRECTORIES="$work" +clone() { git --no-replace-objects -c safe.directory='*' -C "$inputs/tree-sitter-typescript" "$@"; } +# Folders' files hashed as git trees, every file of each, in a repository of this build's own. +hashes="$work/hashes.git" +git init --quiet --bare "$hashes" +tree_of() (cd "$1" && export GIT_DIR="$hashes" GIT_WORK_TREE=. GIT_INDEX_FILE="$hashes/index.$2" && git -c core.autocrlf=false add --all --force && git write-tree) + +# 1. The upstream tree: its pinned commit's, every file of it hashed again here. The clone's refs, replace objects and +# working files say nothing: only a tree whose hash is the one inputs.sh pins is built from or read as upstream's corpus. +mkdir "$work/upstream" +clone archive --format=tar "$upstream_commit" | tar -xf - -C "$work/upstream" +got=$(tree_of "$work/upstream" upstream) +[ "$got" = "$upstream_tree" ] || { echo "build-phase.sh: upstream's commit $upstream_commit extracts as the tree $got, not $upstream_tree" >&2; exit 1; } +chmod -R a-w "$work/upstream" + +# 2. The patch, applied to a copy of the clean tree, may change the two files it is for and nothing else. +cp -R "$work/upstream" "$work/applied" && chmod -R u+w "$work/applied" +(cd "$work/applied" && git apply "$here/coherence.patch") +allowed=$(printf ':100644 100644 M\t%s\n' common/define-grammar.js common/scanner.h) +applied=$(tree_of "$work/applied" applied) +# One line per path changed, with its modes and status, as git diff-tree --raw prints it, renames unpaired. +changed=$(git --git-dir="$hashes" diff-tree -r --raw --no-renames --abbrev=40 "$upstream_tree" "$applied") +outside=$(printf '%s\n' "$changed" | sed 's/ [0-9a-f]\{40\} [0-9a-f]\{40\} / /' | grep -vxF "$allowed" || true) +[ -z "$outside" ] || { printf 'build-phase.sh: coherence.patch may change common/define-grammar.js and common/scanner.h alone, as regular files; it changes:\n%s\n' "$outside" >&2; exit 1; } + +gunzip -c "$inputs/$cli_file" > "$work/tree-sitter" && chmod 755 "$work/tree-sitter" +mkdir "$work/wasi-sdk" "$work/binaryen" "$work/typescript" "$work/web-tree-sitter" +tar -xzf "$inputs/$sdk_file" -C "$work/wasi-sdk" --strip-components=1 +tar -xzf "$inputs/$opt_file" -C "$work/binaryen" --strip-components=1 +tar -xzf "$inputs/$typescript_file" -C "$work/typescript" --strip-components=1 +tar -xzf "$inputs/$runtime_file" -C "$work/web-tree-sitter" --strip-components=1 +# The CLI compiles with these and nothing else, and keeps its caches and configuration (the corpus's native parsers +# among them) in this build's own folder, so no other build's parser is ever tested in place of this one's. +export TREE_SITTER_WASI_SDK_PATH="$work/wasi-sdk" TREE_SITTER_BINARYEN_PATH="$work/binaryen" +export XDG_CACHE_HOME="$work/cache" XDG_CONFIG_HOME="$work/config" TREE_SITTER_LIBDIR="$work/cache/lib" +ts() { "$work/tree-sitter" "$@"; } + +# 3. Each grammar a copy of the clean tree; the patched one takes the two files the patch is for from the applied copy, +# and nothing else from it. +for tree in stock patched; do + mkdir "$work/$tree-wasm" + cp -R "$work/upstream" "$work/$tree" && chmod -R u+w "$work/$tree" + rm -rf "$work/$tree/test" + # The grammar extends tree-sitter-javascript's; v0.23.2's lockfile pins 0.23.1. + mkdir -p "$work/$tree/node_modules/tree-sitter-javascript" + tar -xzf "$inputs/$javascript_file" -C "$work/$tree/node_modules/tree-sitter-javascript" --strip-components=1 +done +for file in common/define-grammar.js common/scanner.h; do cp "$work/applied/$file" "$work/patched/$file"; done +rm -rf "$work/applied" +for tree in stock patched; do + for dialect in typescript tsx; do (cd "$work/$tree/$dialect" && ts generate); done +done + +# 4. Each dialect's corpus in its own folder of the patched grammar, from the clean tree's test/corpus and this folder's +# coherence*.txt: the other dialect's tagged case left out and the tags dropped, since the CLI cannot load a dialect by +# name from inside a grammar's own tree; coherence-tsx.txt is read by the TSX grammar alone. +cd "$work/patched" +for dialect in typescript tsx; do + mkdir -p "$dialect/test/corpus" + for file in "$work/upstream/test/corpus/"*.txt "$here/corpus/"coherence*.txt; do + [ "$(basename "$file")" = coherence-tsx.txt ] && [ "$dialect" != tsx ] && continue + sed '/^:language(/d' "$file" > "$dialect/test/corpus/$(basename "$file")" + done + other="Type arguments in JSX"; [ "$dialect" = tsx ] && other="Type assertions" + (cd "$dialect" && ts test -e "^$other\$") +done + +for tree in stock patched; do + for dialect in typescript tsx; do (cd "$work/$tree/$dialect" && ts build --wasm --output "$work/$tree-wasm/tree-sitter-$dialect.wasm"); done +done + +# 5. The comparison, over the clean tree's corpus and this folder's. +node "$here/compare.mjs" --runtime "$work/web-tree-sitter" --stock "$work/stock-wasm" --patched "$work/patched-wasm" \ + --intended "$here/intended-differences.json" --cases "$work/upstream/test/corpus" --cases "$here/corpus" \ + --files "$work/typescript/lib" --files "$repo/src" --files "$repo/mods" + +# 6. The digests. +for dialect in typescript tsx; do + want=$(digest_in "$here/parsers.sha256" "tree-sitter-$dialect.wasm") + got=$(sha256 "$work/patched-wasm/tree-sitter-$dialect.wasm") + [ -n "$want" ] && [ "$got" = "$want" ] || { echo "build-phase.sh: tree-sitter-$dialect.wasm is $got, not ${want:-a digest parsers.sha256 records}" >&2; exit 1; } +done +mkdir -p "$out" +for dialect in typescript tsx; do cp "$work/patched-wasm/tree-sitter-$dialect.wasm" "$out/" && chmod 644 "$out/tree-sitter-$dialect.wasm"; done +echo "build-phase.sh: both parsers rebuilt byte for byte, and every difference from the stock parsers is intended" diff --git a/grammars/tree-sitter-typescript/build.sh b/grammars/tree-sitter-typescript/build.sh new file mode 100755 index 00000000..e9a6645f --- /dev/null +++ b/grammars/tree-sitter-typescript/build.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# Builds plugins/typescript's two parsers, tree-sitter-typescript.wasm and tree-sitter-tsx.wasm, from +# tree-sitter-typescript v0.23.2 with coherence.patch applied. Upstream has merged no grammar change since +# v0.23.2 (2024-11), and each of these parse errors hides the declarations after it: +# - an import type with type arguments, or as an array's element, an indexed type's object, keyof's operand +# or a type argument: import('x').T, import('x').T[], keyof import('x').T; +# - a member named in or instanceof (in: T, in?: T, in = 2, in?(): void), or a member or a statement whose name +# begins with in and a character that continues a name but is no letter (in_progress, in$, in2(): T, in_x()), +# on the line after another; +# - a bare & in JSX text or a JSX string: Billing & Usage, to="?a=1&b=2", title='Q&'. +# Two phases. fetch.sh downloads every input, each checked by the digest inputs.sha256 records, and clones the +# upstream grammar at its pinned commit. build-phase.sh then runs with the network denied, so it can download +# nothing: it checks every input again, builds the stock and the patched parsers from the pinned upstream tree, +# refuses a patch that changes anything but the grammar and its scanner, runs upstream's corpus and Coherence's +# (corpus/, outside the patch), compares what the two read over a fixed corpus (compare.mjs, against +# intended-differences.json), and writes the bundled parsers only once each is byte for byte the digest +# parsers.sha256 records. A change to the patch updates those digests with it. +# The denial is the sandbox's: sandbox-exec on macOS, which denies this process tree's own sockets (a daemon it asks +# over a mach port may still reach the network for it); on Linux, docker with --network none, as CI runs it, where +# docker is; else unshare -rn, which takes the network namespace away but leaves every unix socket on the filesystem +# reachable (a docker daemon's, a proxy's), so build.sh says so when it falls back to it. +set -eu +here=$(cd "$(dirname "$0")" && pwd) +out=$(cd "$here/../../plugins/typescript" && pwd) +inputs=$(mktemp -d) +trap 'rm -rf "${inputs:?}"' EXIT +"$here/fetch.sh" "$inputs" +case "$(uname -s)" in + Darwin) sandbox-exec -p '(version 1) (allow default) (deny network*)' "$here/build-phase.sh" "$inputs" "$out" ;; + Linux) + . "$here/inputs.sh" + if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then + docker run --rm --network none --user "$(id -u):$(id -g)" \ + --volume "$here/../..:/repo:ro" --volume "$inputs:/inputs:ro" --volume "$out:/out" \ + "$build_image" /repo/grammars/tree-sitter-typescript/build-phase.sh /inputs /out + else + unshare -rn true 2>/dev/null || { echo "build.sh: neither docker nor unshare -rn can deny this machine's network; run build-phase.sh as CI does, in docker with --network none (.github/workflows/ci.yml)" >&2; exit 1; } + echo "build.sh: no docker here, so the build phase runs under unshare -rn, which denies the network but leaves the unix sockets on this machine's filesystem reachable" >&2 + unshare -rn "$here/build-phase.sh" "$inputs" "$out" + fi ;; + *) echo "build.sh: no way to deny the network on $(uname -s)" >&2; exit 1 ;; +esac diff --git a/grammars/tree-sitter-typescript/coherence.patch b/grammars/tree-sitter-typescript/coherence.patch new file mode 100644 index 00000000..83fc5b88 --- /dev/null +++ b/grammars/tree-sitter-typescript/coherence.patch @@ -0,0 +1,197 @@ +diff --git a/common/define-grammar.js b/common/define-grammar.js +index efb0b76..d6e5b2a 100644 +--- a/common/define-grammar.js ++++ b/common/define-grammar.js +@@ -257,6 +257,34 @@ module.exports = function defineGrammar(dialect) { + ), + ), + ++ // A JSX string reads a bare '&' (to="x?a=1&b=2", title='Q&') as text; tree-sitter-javascript reads only an ++ // '&' that starts a character reference or is followed by neither '#' nor a letter, and one before the ++ // closing quote took the quote with it. ++ unescaped_double_jsx_string_fragment: _ => token.immediate(prec(1, /([^"&]|&[^#A-Za-z"])+/)), ++ unescaped_single_jsx_string_fragment: _ => token.immediate(prec(1, /([^'&]|&[^#A-Za-z'])+/)), ++ _jsx_string: $ => choice( ++ seq( ++ '"', ++ repeat(choice( ++ alias($.unescaped_double_jsx_string_fragment, $.string_fragment), ++ $.html_character_reference, ++ // A pattern, not the string '&': a string would be one token with every & operator, renamed with it. ++ alias(token.immediate(/&/), $.string_fragment), ++ )), ++ '"', ++ ), ++ seq( ++ '\'', ++ repeat(choice( ++ alias($.unescaped_single_jsx_string_fragment, $.string_fragment), ++ $.html_character_reference, ++ // A pattern, not the string '&': a string would be one token with every & operator, renamed with it. ++ alias(token.immediate(/&/), $.string_fragment), ++ )), ++ '\'', ++ ), ++ ), ++ + // This rule is only referenced by expression when the dialect is 'tsx' + jsx_opening_element: $ => prec.dynamic(-1, seq( + $._jsx_start_opening_element, +@@ -691,7 +719,9 @@ module.exports = function defineGrammar(dialect) { + // required beforehand. This allows for parsing of annotations such as + // foo: import('x').y.z; + // but was a nightmare to get working. +- _type_query_member_expression_in_type_annotation: $ => seq( ++ // Right-associative so a `<` after the property opens its type arguments, as TypeScript reads ++ // `x as import('a').T`. ++ _type_query_member_expression_in_type_annotation: $ => prec.right(seq( + field('object', choice( + $.import, + alias($._type_query_member_expression_in_type_annotation, $.member_expression), +@@ -702,7 +732,9 @@ module.exports = function defineGrammar(dialect) { + $.private_property_identifier, + alias($.identifier, $.property_identifier), + )), +- ), ++ // import('x').T: the type arguments of an imported generic type. ++ optional(field('type_arguments', $.type_arguments)), ++ )), + _type_query_call_expression_in_type_annotation: $ => seq( + field('function', choice( + $.import, +@@ -726,8 +758,6 @@ module.exports = function defineGrammar(dialect) { + $.readonly_type, + $.constructor_type, + $.infer_type, +- prec(-1, alias($._type_query_member_expression_in_type_annotation, $.member_expression)), +- prec(-1, alias($._type_query_call_expression_in_type_annotation, $.call_expression)), + ), + + tuple_parameter: $ => seq( +@@ -782,6 +812,10 @@ module.exports = function defineGrammar(dialect) { + $.intersection_type, + $.union_type, + 'const', ++ // An import type is a primary type, so it is an array's element (import('x').T[]), an indexed ++ // type's object, keyof's operand and a type argument, as TypeScript reads it. ++ prec(-1, alias($._type_query_member_expression_in_type_annotation, $.member_expression)), ++ prec(-1, alias($._type_query_call_expression_in_type_annotation, $.call_expression)), + ), + + template_type: $ => seq('${', choice($.primary_type, $.infer_type), '}'), +diff --git a/common/scanner.h b/common/scanner.h +index 23b78b5..e81808f 100644 +--- a/common/scanner.h ++++ b/common/scanner.h +@@ -19,6 +19,25 @@ static void advance(TSLexer *lexer) { lexer->advance(lexer, false); } + + static void skip(TSLexer *lexer) { lexer->advance(lexer, true); } + ++// Whether c is JavaScript's white space or a line terminator beyond ASCII, which ends a name as a space does. ++static bool is_unicode_space(int32_t c) { ++ return c == 0xA0 || c == 0x1680 || (c >= 0x2000 && c <= 0x200A) || c == 0x2028 || c == 0x2029 || c == 0x202F || ++ c == 0x205F || c == 0x3000 || c == 0xFEFF; ++} ++ ++// Whether c can continue an identifier, so `in` or `instanceof` before it is only a prefix of a longer ++// name (in_progress, $in, instanceId2), never the operator. ++static bool is_identifier_part(int32_t c) { return iswalnum(c) || c == '_' || c == '$' || c == '\\' || (c > 0x7F && !is_unicode_space(c)); } ++ ++// After a word that is a member's name or an operator (in, instanceof): whether the line before ends, as it does before a member, ++// since no expression continues with `in :`, `in ?` or `in =`. ++static bool member_follows(TSLexer *lexer) { ++ while (iswspace(lexer->lookahead) || is_unicode_space(lexer->lookahead)) { ++ skip(lexer); ++ } ++ return lexer->lookahead == ':' || lexer->lookahead == '?' || lexer->lookahead == '='; ++} ++ + static bool scan_template_chars(TSLexer *lexer) { + lexer->result_symbol = TEMPLATE_CHARS; + for (bool has_content = false;; has_content = true) { +@@ -172,8 +191,9 @@ static bool scan_automatic_semicolon(TSLexer *lexer, const bool *valid_symbols, + } + skip(lexer); + +- if (!iswalpha(lexer->lookahead)) { +- return false; ++ if (!is_identifier_part(lexer->lookahead)) { ++ // A member named `in` (`in: number`, `in?: T`, `in = 2`). ++ return member_follows(lexer); + } + + for (unsigned i = 0; i < 8; i++) { +@@ -183,8 +203,9 @@ static bool scan_automatic_semicolon(TSLexer *lexer, const bool *valid_symbols, + skip(lexer); + } + +- if (!iswalpha(lexer->lookahead)) { +- return false; ++ if (!is_identifier_part(lexer->lookahead)) { ++ // A member named `instanceof`. ++ return member_follows(lexer); + } + break; + } +@@ -273,6 +294,33 @@ static bool scan_closing_comment(TSLexer *lexer) { + return true; + } + ++// Whether the lexer, at an '&', stands at a character reference (& { {). It consumes what it ++// reads; the caller has marked the end before the '&'. ++static bool at_character_reference(TSLexer *lexer) { ++ advance(lexer); ++ unsigned digits = 0; ++ if (lexer->lookahead == '#') { ++ advance(lexer); ++ if (lexer->lookahead == 'x' || lexer->lookahead == 'X') { ++ advance(lexer); ++ for (; digits < 6 && iswxdigit(lexer->lookahead); digits++) { ++ advance(lexer); ++ } ++ } else { ++ for (; digits < 5 && iswdigit(lexer->lookahead); digits++) { ++ advance(lexer); ++ } ++ } ++ } else { ++ for (; digits < 30 && ((lexer->lookahead >= 'a' && lexer->lookahead <= 'z') || ++ (lexer->lookahead >= 'A' && lexer->lookahead <= 'Z')); ++ digits++) { ++ advance(lexer); ++ } ++ } ++ return digits > 0 && lexer->lookahead == ';'; ++} ++ + static bool scan_jsx_text(TSLexer *lexer) { + // saw_text will be true if we see any non-whitespace content, or any whitespace content that is not a newline and + // does not immediately follow a newline. +@@ -282,7 +330,18 @@ static bool scan_jsx_text(TSLexer *lexer) { + bool at_newline = false; + + while (lexer->lookahead != 0 && lexer->lookahead != '<' && lexer->lookahead != '>' && lexer->lookahead != '{' && +- lexer->lookahead != '}' && lexer->lookahead != '&') { ++ lexer->lookahead != '}') { ++ if (lexer->lookahead == '&') { ++ // A character reference ends the text before it; a bare '&' (Billing & Usage) is text. ++ lexer->mark_end(lexer); ++ if (at_character_reference(lexer)) { ++ lexer->result_symbol = JSX_TEXT; ++ return saw_text; ++ } ++ saw_text = true; ++ at_newline = false; ++ continue; ++ } + bool is_wspace = iswspace(lexer->lookahead); + if (lexer->lookahead == '\n') { + at_newline = true; +@@ -310,6 +369,7 @@ static bool scan_jsx_text(TSLexer *lexer) { + advance(lexer); + } + ++ lexer->mark_end(lexer); + lexer->result_symbol = JSX_TEXT; + return saw_text; + } diff --git a/grammars/tree-sitter-typescript/compare.mjs b/grammars/tree-sitter-typescript/compare.mjs new file mode 100644 index 00000000..7fd1944f --- /dev/null +++ b/grammars/tree-sitter-typescript/compare.mjs @@ -0,0 +1,391 @@ +// Compares what the patched TypeScript parsers read against what the stock ones read, over a fixed corpus, node by +// node: every node's type, whether it is named, its span, its field and whether it is an error or a missing node. +// Each difference is one region, the smallest run of sibling nodes outside which the two trees agree, and every +// region must be one the patch intends, as intended-differences.json names it by its construct, never by its place: +// what kind of difference it is (an improvement, where the stock parser errs and the patched one does not; a +// regression, the other way about; both erring, differently; or a reshape, neither erring), in which dialects, and a +// tree-sitter query whose capture the region overlaps. Every token the patched parsers read is also held to the stock +// parsers' own reading of its spelling: a keyword or a mark read as a type the stock parsers never read it as (a token +// renamed or aliased) fails wherever it stands, an improvement's region among it: no intended difference renames one. +// Each intended difference names the corpus cases it must show in, one form to a case, and fails unless each of those +// cases, in each of its dialects, holds exactly one region of difference and that region is one it allows: a form that +// breaks back to the stock reading, or into another difference, fails in its own case, whatever the others show. A +// corpus case no entry names, in any corpus (upstream's, Coherence's, limits.txt), must read exactly as the stock +// parsers read it: any region of difference in it fails, whatever an entry's query overlaps, so a form the patch is +// not meant to touch cannot change unnoticed under an entry whose query happens to reach it; a file's regions, which no +// entry names, are allowed by an entry's kind, dialects and query alone. The patched parsers are also held to every +// expected tree the corpus declares, the whole tree, as tree-sitter test holds the native build: an improvement's case +// must declare one, so a form is held to its fixed reading, not merely to reading with no error. The corpus is read +// from where the patch cannot write: the clean upstream tree and this folder. +// +// node compare.mjs --runtime --stock --patched --intended +// --cases ... --files ... +// Each parser folder holds tree-sitter-typescript.wasm and tree-sitter-tsx.wasm. --cases reads every *.txt in the +// folder as tree-sitter's corpus format, each case an input with the tree it expects, if any; --files reads every .ts, +// .tsx, .mts and .cts below the folder, node_modules left out. Every input is read by both dialects for the comparison; +// an expected tree holds the dialects its case is for (those its :language attributes name, the TSX grammar alone for a +// file named *-tsx.txt, else both). Exits 1 on any difference no entry allows, any difference in a case no entry names, +// or any expected tree not read. + +import { readdirSync, readFileSync } from "node:fs"; +import { basename, join, relative } from "node:path"; +import { pathToFileURL } from "node:url"; +import { parseArgs } from "node:util"; + +const DIALECTS = ["typescript", "tsx"]; + +const { values: options } = parseArgs({ + options: { + runtime: { type: "string" }, + stock: { type: "string" }, + patched: { type: "string" }, + intended: { type: "string" }, + cases: { type: "string", multiple: true, default: [] }, + files: { type: "string", multiple: true, default: [] }, + }, +}); +for (const required of ["runtime", "stock", "patched", "intended"]) { + if (options[required] === undefined) fail(`--${required} is required`); +} + +function fail(message) { + console.error(`compare.mjs: ${message}`); + process.exit(1); +} + +// --- Inputs ------------------------------------------------------------------------------------------------------ + +/** The cases of one file in tree-sitter's corpus format: a name between two rows of =, the input, a row of -, its tree. */ +function casesOf(text) { + const lines = text.split("\n"); + const header = /^(={3,})(\S*?)\s*$/; + const cases = []; + let i = 0; + while (i < lines.length) { + const open = header.exec(lines[i]); + if (open === null) { i++; continue; } + const suffix = open[2]; + let j = i + 1; + const names = []; + while (j < lines.length && header.exec(lines[j])?.[2] !== suffix) names.push(lines[j++]); + const divider = new RegExp(`^-{3,}${suffix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*$`); + let k = j + 1; + const body = []; + while (k < lines.length && !divider.test(lines[k])) body.push(lines[k++]); + let next = k + 1; + while (next < lines.length && !header.test(lines[next])) next++; + const name = names.filter((line) => !line.startsWith(":")).join(" ").trim(); + const languages = names.flatMap((line) => /^:language\((\w+)\)\s*$/.exec(line)?.[1] ?? []); + const expected = normalized(lines.slice(k + 1, next).join("\n")); + cases.push({ name, languages, expected: expected === "" ? null : expected, text: body.join("\n").replace(/^\n+/, "").replace(/\n+$/, "\n") }); + i = next; + } + return cases; +} + +/** An S-expression as tree-sitter test compares one: white space collapsed, none inside a parenthesis's edge. */ +function normalized(sexp) { + return sexp.replace(/\s+/g, " ").replace(/\( /g, "(").replace(/ \)/g, ")").trim(); +} + +function inputs() { + const all = []; + let before = 0; + const from = (folder) => { + if (all.length === before) fail(`${folder} holds no input`); + before = all.length; + }; + for (const folder of options.cases) { + for (const file of readdirSync(folder).filter((f) => f.endsWith(".txt")).sort()) { + const seen = new Map(); + for (const c of casesOf(readFileSync(join(folder, file), "utf8"))) { + const label = `${basename(file, ".txt")}: ${c.name}`; + const n = (seen.get(label) ?? 0) + 1; + seen.set(label, n); + const dialects = c.languages.length > 0 ? c.languages : basename(file, ".txt").endsWith("-tsx") ? ["tsx"] : DIALECTS; + if (dialects.some((d) => !DIALECTS.includes(d))) fail(`${label}: no dialect ${dialects.join(", ")}`); + all.push({ key: n === 1 ? label : `${label} (${n})`, text: c.text, expected: c.expected, dialects, isCase: true }); + } + } + from(folder); + } + for (const folder of options.files) { + const walk = (dir) => { + for (const entry of readdirSync(dir, { withFileTypes: true }).sort((a, b) => (a.name < b.name ? -1 : 1))) { + const path = join(dir, entry.name); + if (entry.isDirectory()) { if (entry.name !== "node_modules") walk(path); } + else if (/\.[mc]?tsx?$/.test(entry.name)) all.push({ key: `${basename(folder)}/${relative(folder, path)}`, text: readFileSync(path, "utf8"), expected: null, dialects: [], isCase: false }); + } + }; + walk(folder); + from(folder); + } + return all; +} + +// --- Trees ------------------------------------------------------------------------------------------------------- + +const ERROR = "ERROR"; + +/** A tree flattened in preorder: each node's type, named-ness, missing-ness, span, field and depth, and its children. */ +function flatten(tree, text) { + const nodes = []; + const leaves = []; + const cursor = tree.walk(); + const stack = []; + for (let more = true; more; ) { + const index = nodes.length; + const node = { + type: cursor.nodeType, + named: cursor.nodeIsNamed, + missing: cursor.nodeIsMissing, + start: cursor.startIndex, + end: cursor.endIndex, + field: cursor.currentFieldName ?? "", + children: [], + errs: false, + }; + nodes.push(node); + if (stack.length > 0) nodes[stack.at(-1)].children.push(index); + if (cursor.gotoFirstChild()) { stack.push(index); continue; } + if (node.end > node.start) leaves.push({ type: node.type, named: node.named, start: node.start, end: node.end, text: text.slice(node.start, node.end) }); + while (!cursor.gotoNextSibling()) { + if (!cursor.gotoParent()) { more = false; break; } + stack.pop(); + } + } + cursor.delete(); + for (let i = nodes.length - 1; i >= 0; i--) { + const node = nodes[i]; + node.errs = node.type === ERROR || node.missing || node.children.some((c) => nodes[c].errs); + } + return { nodes, leaves }; +} + +const keyOf = (n) => `${n.type}\u0000${n.named}\u0000${n.missing}\u0000${n.start}\u0000${n.end}\u0000${n.field}`; + +function sameSubtree(s, si, p, pi) { + const a = s.nodes[si]; + const b = p.nodes[pi]; + if (keyOf(a) !== keyOf(b) || a.children.length !== b.children.length) return false; + return a.children.every((c, k) => sameSubtree(s, c, p, b.children[k])); +} + +/** The regions where two trees of one text differ: runs of siblings under a pair of nodes that agree. */ +function regionsOf(s, p) { + const regions = []; + const run = (sRun, pRun, parent) => { + const spans = [...sRun.map((i) => s.nodes[i]), ...pRun.map((i) => p.nodes[i])]; + regions.push({ + start: Math.min(...spans.map((n) => n.start)), + end: Math.max(...spans.map((n) => n.end)), + parent, + stockErrs: sRun.some((i) => s.nodes[i].errs), + patchedErrs: pRun.some((i) => p.nodes[i].errs), + stockTypes: sRun.map((i) => s.nodes[i].type), + patchedTypes: pRun.map((i) => p.nodes[i].type), + }); + }; + const visit = (si, pi) => { + const sc = s.nodes[si].children; + const pc = p.nodes[pi].children; + let i = 0; + let j = 0; + while (i < sc.length || j < pc.length) { + if (i < sc.length && j < pc.length && keyOf(s.nodes[sc[i]]) === keyOf(p.nodes[pc[j]])) { + if (!sameSubtree(s, sc[i], p, pc[j])) visit(sc[i], pc[j]); + i++; + j++; + continue; + } + // A run: take the next node of each side, then every node of either side that starts before the run ends. + const i0 = i; + const j0 = j; + let end = -1; + if (i < sc.length) end = Math.max(end, s.nodes[sc[i++]].end); + if (j < pc.length) end = Math.max(end, p.nodes[pc[j++]].end); + for (let grew = true; grew; ) { + grew = false; + while (i < sc.length && (s.nodes[sc[i]].start < end || j >= pc.length)) { end = Math.max(end, s.nodes[sc[i++]].end); grew = true; } + while (j < pc.length && (p.nodes[pc[j]].start < end || i >= sc.length)) { end = Math.max(end, p.nodes[pc[j++]].end); grew = true; } + } + run(sc.slice(i0, i), pc.slice(j0, j), s.nodes[si].type); + } + }; + if (keyOf(s.nodes[0]) !== keyOf(p.nodes[0])) run([0], [0], ""); + else visit(0, 0); + return regions; +} + +/** A flattened tree as tree-sitter test prints it: named nodes and missing ones, with their fields when asked. */ +function sexpOf(t, index, fields) { + const node = t.nodes[index]; + const head = node.missing ? `MISSING ${node.named ? node.type : JSON.stringify(node.type)}` : node.type; + const parts = [head]; + for (const c of node.children) { + const child = t.nodes[c]; + if (child.named || child.missing) parts.push(`${fields && child.field !== "" ? `${child.field}: ` : ""}${sexpOf(t, c, fields)}`); + } + return `(${parts.join(" ")})`; +} + +const kindOf = (r) => (r.stockErrs ? (r.patchedErrs ? "both err" : "improvement") : r.patchedErrs ? "regression" : "reshape"); + +// --- The comparison ---------------------------------------------------------------------------------------------- + +const { Parser, Language, Query } = await import(pathToFileURL(join(options.runtime, "web-tree-sitter.js")).href); +await Parser.init(); +const load = async (folder, dialect) => Language.load(readFileSync(join(folder, `tree-sitter-${dialect}.wasm`))); +const parsers = {}; +for (const dialect of DIALECTS) { + parsers[dialect] = {}; + for (const side of ["stock", "patched"]) { + const language = await load(options[side], dialect); + const parser = new Parser(); + parser.setLanguage(language); + parsers[dialect][side] = { language, parser }; + } +} + +const intended = JSON.parse(readFileSync(options.intended, "utf8")); +const KINDS = ["improvement", "regression", "both err", "reshape"]; +const ids = new Set(); +const entries = intended.differences.map((entry) => { + if (ids.has(entry.id)) fail(`intended difference ${entry.id} is listed twice`); + ids.add(entry.id); + if (!KINDS.includes(entry.kind)) fail(`intended difference ${entry.id}: its kind is one of ${KINDS.join(", ")}, not ${entry.kind}`); + if (entry.side !== "stock" && entry.side !== "patched") fail(`intended difference ${entry.id}: its side is stock or patched, not ${entry.side}`); + if (!Array.isArray(entry.dialects) || entry.dialects.length === 0 || entry.dialects.some((d) => !DIALECTS.includes(d))) fail(`intended difference ${entry.id}: its dialects are among ${DIALECTS.join(", ")}`); + if (!Array.isArray(entry.cases) || entry.cases.length === 0) fail(`intended difference ${entry.id}: it names the corpus cases it shows in`); + const queries = {}; + for (const dialect of entry.dialects) { + try { + queries[dialect] = new Query(parsers[dialect][entry.side].language, entry.query); + } catch (error) { + fail(`intended difference ${entry.id}: its query does not compile against the ${entry.side} ${dialect} parser (${error.message})`); + } + } + const tokens = new Set((entry.tokens ?? []).map((t) => `${t.text}\u0000${t.type}\u0000${t.named}`)); + return { ...entry, queries, tokens, seen: new Set(), tokensSeen: new Set() }; +}); + +const failures = []; +const renames = []; +// The cases the entries name, and in each parse of one, the regions and the entries that allow each. +const named = new Set(entries.flatMap((e) => e.cases)); +const parsesOfNamed = new Map(); // case and dialect -> [{ kind, allowing: Set of ids }] +const inputKeys = new Map(); // case -> its input +// A token is known by its spelling: a leaf the stock parsers read as an anonymous token, a keyword or a mark, read by the +// patched parsers as another type is a rename. The symbol's own name cannot say so, since a token used only under an +// alias takes the alias's name in its parser's table. So a patched leaf's spelling and type must be a pair the stock +// parsers show somewhere in the corpus, when the leaf is anonymous and not its own spelling, or named and spelled as +// one of the stock grammar's tokens (keyof as an identifier, & as a string fragment). An intended difference may list +// such a reading in its tokens (a member named instanceof is a property_identifier spelled as a keyword), and it is +// allowed only inside a region that difference allows. +const stockKinds = new Set(); +const patchedKinds = new Map(); // spelling and type -> the first leaf showing it, and where +const tokenSpelled = (language, text) => { + const id = language.idForNodeType(text, false); + return id !== null && id !== 0 && language.nodeTypeIsVisible(id); +}; +const heldToStock = (leaf, dialect) => (leaf.named ? tokenSpelled(parsers[dialect].stock.language, leaf.text) : leaf.type !== leaf.text); +const tally = { inputs: 0, identical: 0, regions: 0, expected: 0 }; +const kindKey = (leaf) => `${leaf.text}\u0000${leaf.type}\u0000${leaf.named}`; +const excerpt = (text, start, end) => JSON.stringify(text.slice(start, Math.min(end, start + 80)) + (end - start > 80 ? "…" : "")); + +for (const input of inputs()) { + tally.inputs++; + inputKeys.set(input.key, input); + for (const dialect of DIALECTS) { + const { stock, patched } = parsers[dialect]; + const sTree = stock.parser.parse(input.text); + const pTree = patched.parser.parse(input.text); + const s = flatten(sTree, input.text); + const p = flatten(pTree, input.text); + for (const leaf of s.leaves) if (heldToStock(leaf, dialect)) stockKinds.add(kindKey(leaf)); + const regions = s.nodes.length === p.nodes.length && s.nodes.every((n, k) => keyOf(n) === keyOf(p.nodes[k])) ? [] : regionsOf(s, p); + if (regions.length === 0) tally.identical++; + tally.regions += regions.length; + const captures = new Map(); + const capturesOf = (entry) => { + if (!captures.has(entry.id)) { + const tree = entry.side === "stock" ? sTree : pTree; + captures.set(entry.id, entry.queries[dialect].captures(tree.rootNode).filter((c) => c.name === "construct").map((c) => ({ start: c.node.startIndex, end: c.node.endIndex }))); + } + return captures.get(entry.id); + }; + // The patched parser reads the case as the tree it expects, whole. + if (input.expected !== null && input.dialects.includes(dialect)) { + tally.expected++; + const read = normalized(sexpOf(p, 0, /\w: \(/.test(input.expected))); + if (read !== input.expected) { + // Where the two first part, a little before it, so the message shows the node that differs. + let at = 0; + while (at < read.length && read[at] === input.expected[at]) at++; + const from = Math.max(0, at - 40); + failures.push(`${input.key} (${dialect}): the patched parser does not read the tree the case expects; from character ${from}, it reads ${excerpt(read, from, from + 80)} where the case expects ${excerpt(input.expected, from, from + 80)}`); + } + } + const parseRegions = named.has(input.key) ? [] : null; + if (parseRegions !== null) parsesOfNamed.set(`${input.key}\u0000${dialect}`, parseRegions); + const allowed = []; + const overlaps = (entry, region) => capturesOf(entry).some((c) => c.start < region.end && region.start < c.end); + for (const region of regions) { + const kind = kindOf(region); + // A corpus case no entry names reads exactly as the stock parsers read it, in every corpus alike: any region of + // difference in it fails, whatever an entry's query overlaps, so no entry's query reaches past the cases it names. + if (input.isCase && parseRegions === null) { + const overlapping = entries.filter((e) => e.dialects.includes(dialect) && overlaps(e, region)).map((e) => e.id); + failures.push(`${input.key} (${dialect}): a case no intended difference names holds ${kind === "improvement" ? "an" : "a"} ${kind} at ${region.start}..${region.end} under ${region.parent || "the root"}, stock ${region.stockTypes.join(" ") || "nothing"}, patched ${region.patchedTypes.join(" ") || "nothing"}: ${excerpt(input.text, region.start, region.end)}; ${overlapping.length === 0 ? "no entry's query overlaps it" : `the query of ${overlapping.join(", ")} overlaps it`}, and a case no entry names must read as the stock parsers read it`); + continue; + } + const allowing = entries.filter((e) => e.kind === kind && e.dialects.includes(dialect) && overlaps(e, region)); + parseRegions?.push({ kind, allowing: new Set(allowing.map((e) => e.id)) }); + for (const entry of allowing) { + entry.seen.add(`${input.key}\u0000${dialect}`); + allowed.push({ region, entry }); + } + if (allowing.length === 0) failures.push(`${input.key} (${dialect}): an unlisted ${kind} at ${region.start}..${region.end} under ${region.parent || "the root"}, stock ${region.stockTypes.join(" ") || "nothing"}, patched ${region.patchedTypes.join(" ") || "nothing"}: ${excerpt(input.text, region.start, region.end)}`); + } + for (const leaf of p.leaves) { + if (!heldToStock(leaf, dialect)) continue; + const key = kindKey(leaf); + const listing = allowed.find(({ region, entry }) => entry.tokens.has(key) && leaf.start >= region.start && leaf.end <= region.end); + if (listing !== undefined) { listing.entry.tokensSeen.add(key); continue; } + if (!patchedKinds.has(key)) patchedKinds.set(key, { leaf, where: `${input.key} (${dialect})`, text: input.text }); + } + sTree.delete(); + pTree.delete(); + } +} + +// Every token the patched parsers read is read as the stock parsers read its spelling somewhere in the corpus. +for (const [key, { leaf, where, text }] of patchedKinds) { + if (stockKinds.has(key)) continue; + renames.push(`${where}: the patched parser reads ${JSON.stringify(leaf.text)} as ${leaf.named ? "named " : ""}${leaf.type}, which the stock parsers never do (a token renamed or aliased), first at ${leaf.start}..${leaf.end}`); +} +// Every intended difference shows in each case it names, in each of its dialects, as that case's one region, and each +// token reading it lists shows in its regions. A case an improvement names declares the tree it fixes the form to. +for (const entry of entries) { + for (const key of entry.tokens) if (!entry.tokensSeen.has(key)) failures.push(`intended difference ${entry.id} lists the token ${key.split("\u0000").slice(0, 2).join(" read as ")}, which none of its regions shows`); + if (entry.seen.size === 0) failures.push(`intended difference ${entry.id} (${entry.construct}) shows in no input`); + for (const name of entry.cases) { + const input = inputKeys.get(name); + if (input === undefined) { failures.push(`intended difference ${entry.id} names ${name}, which no corpus holds`); continue; } + if (entry.kind === "improvement" && (input.expected === null || entry.dialects.some((d) => !input.dialects.includes(d)))) failures.push(`intended difference ${entry.id} names ${name}, which declares no expected tree in each of its dialects (${entry.dialects.join(", ")}): an improvement's form is held to the tree it reads as`); + for (const dialect of entry.dialects) { + const found = parsesOfNamed.get(`${name}\u0000${dialect}`) ?? []; + if (found.length !== 1 || !found[0].allowing.has(entry.id)) failures.push(`intended difference ${entry.id} does not show in ${name} (${dialect}), a case it names, as its one region: it holds ${found.length === 0 ? "none" : found.map((r) => `${r.kind} allowed by ${[...r.allowing].join(", ") || "none"}`).join("; ")}`); + } + } +} + +console.log(`compare.mjs: ${tally.inputs} inputs in ${DIALECTS.length} dialects, ${tally.identical} parses identical, ${tally.regions} regions of difference, ${tally.expected} expected trees`); +for (const entry of entries) console.log(` ${entry.id} (${entry.kind}): ${entry.seen.size} parses`); +if (renames.length + failures.length > 0) { + for (const r of renames) console.error(` ✕ ${r}`); + for (const f of failures.slice(0, 100)) console.error(` ✕ ${f}`); + if (failures.length > 100) console.error(` … and ${failures.length - 100} more`); + fail(`${renames.length} token${renames.length === 1 ? "" : "s"} renamed and ${failures.length} other failure${failures.length === 1 ? "" : "s"}: differences between the stock and patched parsers that intended-differences.json does not allow, any in a case no entry names, intended ones not shown as their cases' one region, or expected trees not read`); +} +console.log("compare.mjs: every difference between the stock and patched parsers is one intended-differences.json allows, each in its own cases, every case no entry names reads as the stock parsers read it, and the patched parsers read every expected tree"); diff --git a/grammars/tree-sitter-typescript/corpus/coherence-tsx.txt b/grammars/tree-sitter-typescript/corpus/coherence-tsx.txt new file mode 100644 index 00000000..7f9dc2f3 --- /dev/null +++ b/grammars/tree-sitter-typescript/corpus/coherence-tsx.txt @@ -0,0 +1,161 @@ +Coherence's own cases for the TSX grammar alone (a file named *-tsx.txt is read by it alone), one form to a case, each +with the whole tree the patched grammar must read it as. Kept out of coherence.patch, as coherence.txt is. + +========================================== +Coherence: a bare ampersand in JSX text +========================================== + +const a =

Read & write

; + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (jsx_element + (jsx_opening_element + (identifier)) + (jsx_text) + (jsx_closing_element + (identifier)))))) + +========================================== +Coherence: a bare ampersand before a letter in a JSX string +========================================== + +const b =
x; + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (jsx_element + (jsx_opening_element + (identifier) + (jsx_attribute + (property_identifier) + (string + (string_fragment) + (string_fragment) + (string_fragment)))) + (jsx_text) + (jsx_closing_element + (identifier)))))) + +========================================== +Coherence: a bare ampersand before a single-quoted JSX string's closing quote +========================================== + +const c = ; + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (jsx_self_closing_element + (identifier) + (jsx_attribute + (property_identifier) + (string + (string_fragment) + (string_fragment))))))) + +========================================== +Coherence: a bare ampersand before a double-quoted JSX string's closing quote +========================================== + +const c = ; + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (jsx_self_closing_element + (identifier) + (jsx_attribute + (property_identifier) + (string + (string_fragment) + (string_fragment))))))) + +========================================== +Coherence: a bare ampersand among character references in JSX text +========================================== + +const d =

& { & {v}

; + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (jsx_element + (jsx_opening_element + (identifier)) + (html_character_reference) + (jsx_text) + (html_character_reference) + (jsx_text) + (jsx_expression + (identifier)) + (jsx_closing_element + (identifier)))))) + +========================================== +Coherence: character references in JSX text and a JSX string +========================================== + +const e =

& ok {

; + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (jsx_element + (jsx_opening_element + (identifier) + (jsx_attribute + (property_identifier) + (string + (string_fragment) + (html_character_reference) + (string_fragment)))) + (html_character_reference) + (jsx_text) + (html_character_reference) + (jsx_closing_element + (identifier)))))) + +========================================== +Coherence: character references at their limits +========================================== + +const e =

􏿿|�|〹|𞉀|&aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;|&aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;

; + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (jsx_element + (jsx_opening_element + (identifier)) + (html_character_reference) + (jsx_text) + (html_character_reference) + (jsx_text) + (html_character_reference) + (jsx_text) + (jsx_closing_element + (identifier)))))) diff --git a/grammars/tree-sitter-typescript/corpus/coherence.txt b/grammars/tree-sitter-typescript/corpus/coherence.txt new file mode 100644 index 00000000..236366f4 --- /dev/null +++ b/grammars/tree-sitter-typescript/corpus/coherence.txt @@ -0,0 +1,690 @@ +Coherence's own cases, one form to a case, each with the whole tree the patched grammar must read it as. Kept here, +out of coherence.patch, so the patch has no way to rewrite what it is held to: build-phase.sh runs them with +tree-sitter test beside upstream's corpus, and compare.mjs holds the bundled parsers to each tree and each intended +difference to the cases it names. The forms the patch fixes, and forms beside them it must leave as the stock grammar +reads them. + +========================================== +Coherence: an import type with type arguments in a union +========================================== + +interface A { b: null | import('../api').Page; c: number } + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (union_type + (literal_type + (null)) + (member_expression + (call_expression + (import) + (arguments + (string + (string_fragment)))) + (property_identifier) + (type_arguments + (type_identifier)))))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: an import type with type arguments as an alias's type +========================================== + +type L = import('kea').Logic<{ a: 1 }> + +--- + +(program + (type_alias_declaration + (type_identifier) + (member_expression + (call_expression + (import) + (arguments + (string + (string_fragment)))) + (property_identifier) + (type_arguments + (object_type + (property_signature + (property_identifier) + (type_annotation + (literal_type + (number))))))))) + +========================================== +Coherence: an import type as an array's element +========================================== + +type C = import('../x').Column[]; + +--- + +(program + (type_alias_declaration + (type_identifier) + (array_type + (member_expression + (call_expression + (import) + (arguments + (string + (string_fragment)))) + (property_identifier))))) + +========================================== +Coherence: an import type as keyof's operand +========================================== + +type K = keyof import('~/types').Criteria; + +--- + +(program + (type_alias_declaration + (type_identifier) + (index_type_query + (member_expression + (call_expression + (import) + (arguments + (string + (string_fragment)))) + (property_identifier))))) + +========================================== +Coherence: an import type with type arguments as an indexed type's object +========================================== + +type I = import('x').T['k']; + +--- + +(program + (type_alias_declaration + (type_identifier) + (lookup_type + (member_expression + (call_expression + (import) + (arguments + (string + (string_fragment)))) + (property_identifier) + (type_arguments + (type_identifier))) + (literal_type + (string + (string_fragment)))))) + +========================================== +Coherence: an import type as an array's element in a type argument +========================================== + +type R = Record; + +--- + +(program + (type_alias_declaration + (type_identifier) + (generic_type + (type_identifier) + (type_arguments + (predefined_type) + (array_type + (member_expression + (call_expression + (import) + (arguments + (string + (string_fragment)))) + (property_identifier))))))) + +========================================== +Coherence: a property named in after another member +========================================== + +interface M { + a: number + in?: number +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a property named instanceof after another member +========================================== + +interface M { + b: number + instanceof: string +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a property named in_progress after another member +========================================== + +interface M { + c: number + in_progress: number +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a property named instanceof_x after another member +========================================== + +interface M { + d: number + instanceof_x: number +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a property named in$ after another member +========================================== + +interface N { + a: number + in$: number +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a property named in2 after another member +========================================== + +interface N { + b: number + in2: number +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a property named in\u0061 after another member +========================================== + +interface N { + d: number + in\u0061: number +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a property named instanceof$ after another member +========================================== + +interface N { + e: number + instanceof$: number +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a property named in_x in a type literal after another member +========================================== + +type O = { + a: number + in_x: string +} + +--- + +(program + (type_alias_declaration + (type_identifier) + (object_type + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a class field named in after another field +========================================== + +class K { + a = 1 + in = 2 +} + +--- + +(program + (class_declaration + (type_identifier) + (class_body + (public_field_definition + (property_identifier) + (number)) + (public_field_definition + (property_identifier) + (number))))) + +========================================== +Coherence: a method signature named in_x after another member +========================================== + +interface I { + a(): void + in_x(): void +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (method_signature + (property_identifier) + (formal_parameters) + (type_annotation + (predefined_type))) + (method_signature + (property_identifier) + (formal_parameters) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a generic method signature named in2 after another member +========================================== + +interface G { + a: number + in2(): T +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (method_signature + (property_identifier) + (type_parameters + (type_parameter + (type_identifier))) + (formal_parameters) + (type_annotation + (type_identifier)))))) + +========================================== +Coherence: an optional method signature named in after another member +========================================== + +interface P { + a: number + in?(): void +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (method_signature + (property_identifier) + (formal_parameters) + (type_annotation + (predefined_type)))))) + +========================================== +Coherence: a method named in_progress after a field +========================================== + +class C { + a = 1 + in_progress() {} +} + +--- + +(program + (class_declaration + (type_identifier) + (class_body + (public_field_definition + (property_identifier) + (number)) + (method_definition + (property_identifier) + (formal_parameters) + (statement_block))))) + +========================================== +Coherence: a method signature named in_x in a declared class after a field +========================================== + +declare class Q { + a: number + in_x(): void +} + +--- + +(program + (ambient_declaration + (class_declaration + (type_identifier) + (class_body + (public_field_definition + (property_identifier) + (type_annotation + (predefined_type))) + (method_signature + (property_identifier) + (formal_parameters) + (type_annotation + (predefined_type))))))) + +========================================== +Coherence: a statement beginning with in_x after another +========================================== + +const a = 1 +in_x() + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (number))) + (expression_statement + (call_expression + (identifier) + (arguments)))) + +========================================== +Coherence: a statement beginning with in$ after another +========================================== + +foo() +in$.bar() + +--- + +(program + (expression_statement + (call_expression + (identifier) + (arguments))) + (expression_statement + (call_expression + (member_expression + (identifier) + (property_identifier)) + (arguments)))) + +========================================== +Coherence: members whose names begin with in and a letter after another member +========================================== + +interface U { + a: number + index: number + input: string + init(): void + inü: number +} +class V { + a = 1 + index = 2 + init() {} +} + +--- + +(program + (interface_declaration + (type_identifier) + (interface_body + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type))) + (method_signature + (property_identifier) + (formal_parameters) + (type_annotation + (predefined_type))) + (property_signature + (property_identifier) + (type_annotation + (predefined_type))))) + (class_declaration + (type_identifier) + (class_body + (public_field_definition + (property_identifier) + (number)) + (public_field_definition + (property_identifier) + (number)) + (method_definition + (property_identifier) + (formal_parameters) + (statement_block))))) + +========================================== +Coherence: in and instanceof continue an expression across lines +========================================== + +const r1 = a + in b +const r2 = a + instanceof B +const r3 = a + in b +const r4 = a + instanceof B +for (const k +in o) {} + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (binary_expression + (identifier) + (identifier)))) + (lexical_declaration + (variable_declarator + (identifier) + (binary_expression + (identifier) + (identifier)))) + (lexical_declaration + (variable_declarator + (identifier) + (binary_expression + (identifier) + (identifier)))) + (lexical_declaration + (variable_declarator + (identifier) + (binary_expression + (identifier) + (identifier)))) + (for_in_statement + (identifier) + (identifier) + (statement_block))) + +========================================== +Coherence: in and instanceof continue an expression across lines before a parenthesis +========================================== + +const r5 = key + in (record) +const r6 = value + instanceof (Date) + +--- + +(program + (lexical_declaration + (variable_declarator + (identifier) + (binary_expression + (identifier) + (parenthesized_expression + (identifier))))) + (lexical_declaration + (variable_declarator + (identifier) + (binary_expression + (identifier) + (parenthesized_expression + (identifier)))))) diff --git a/grammars/tree-sitter-typescript/corpus/limits.txt b/grammars/tree-sitter-typescript/corpus/limits.txt new file mode 100644 index 00000000..79f9fe6f --- /dev/null +++ b/grammars/tree-sitter-typescript/corpus/limits.txt @@ -0,0 +1,57 @@ +Forms compare.mjs reads beside the grammar's corpus and Coherence's: the one the patch reads worse than the stock +grammar (a comparison after an import type, which intended-differences.json lists as a regression and names as its +case), and those both grammars still err on, which must stay as the stock grammar reads them: compare.mjs fails on any +region of difference in a case no entry names, whatever an entry's query overlaps. No expected trees: the comparison's +only reference is the stock parser. + +================== +a comparison after an import type +================== + +const a = x as import('x').T < y; +const b = 1; + +--- + +================== +an optional destructured parameter in a function type +================== + +type F = ({ a }?: T) => U; + +--- + +================== +a parenthesized import type +================== + +type P = (import('x').T)[]; + +--- + +================== +typeof an import type as a call's type argument +================== + +const m = importOriginal(); + +--- + +================== +a method named in after another member +================== + +class C { + a = 1 + in() {} +} + +--- + +================== +variance annotations +================== + +type V = T; + +--- diff --git a/grammars/tree-sitter-typescript/fetch.sh b/grammars/tree-sitter-typescript/fetch.sh new file mode 100755 index 00000000..19bfb61c --- /dev/null +++ b/grammars/tree-sitter-typescript/fetch.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# The fetch phase: downloads every input the build phase reads into the folder given, each checked against the digest +# inputs.sha256 records for it, and clones the upstream grammar at its pinned commit. The only phase that reaches the +# network; build-phase.sh checks all of it again, with the network denied, before it builds from any of it. +# Needs curl and git. +set -eu +here=$(cd "$(dirname "$0")" && pwd) +. "$here/inputs.sh" +[ $# -eq 1 ] || { echo "usage: fetch.sh " >&2; exit 2; } +mkdir -p "$1" +dir=$(cd "$1" && pwd) +for file in $input_files; do + want=$(digest_in "$here/inputs.sha256" "$file") + [ -n "$want" ] || { echo "fetch.sh: inputs.sha256 records no digest for $file" >&2; exit 1; } + curl --fail --silent --show-error --location --output "$dir/$file" "$(url_of "$file")" + got=$(sha256 "$dir/$file") + [ "$got" = "$want" ] || { rm -f "$dir/$file"; echo "fetch.sh: $file is $got, not $want" >&2; exit 1; } +done +git clone --quiet "$upstream" "$dir/tree-sitter-typescript" +git -C "$dir/tree-sitter-typescript" checkout --quiet "$upstream_commit" diff --git a/grammars/tree-sitter-typescript/inputs.sh b/grammars/tree-sitter-typescript/inputs.sh new file mode 100644 index 00000000..1b376800 --- /dev/null +++ b/grammars/tree-sitter-typescript/inputs.sh @@ -0,0 +1,38 @@ +# Sourced by fetch.sh and build-phase.sh: the inputs this machine builds from, by the file names inputs.sha256 lists +# their digests under, where each comes from, and the upstream commit and its tree. Defines names and helpers and runs nothing. +upstream=https://github.com/tree-sitter/tree-sitter-typescript +upstream_commit=f975a621f4e7f532fe322e13c4f79495e0a7b2e7 # v0.23.2 +# That commit's tree: the build phase hashes the files it extracts from the commit and builds from them only when they are this tree. +upstream_tree=4c27006c60e37ddd0c30a4afecab363dc9d84575 +case "$(uname -s)-$(uname -m)" in + Darwin-arm64) cli=macos-arm64 sdk=arm64-macos opt=arm64-macos ;; + Darwin-x86_64) cli=macos-x64 sdk=x86_64-macos opt=x86_64-macos ;; + Linux-x86_64) cli=linux-x64 sdk=x86_64-linux opt=x86_64-linux ;; + Linux-aarch64 | Linux-arm64) cli=linux-arm64 sdk=arm64-linux opt=aarch64-linux ;; + *) echo "inputs.sh: no pinned compiler for $(uname -s) $(uname -m)" >&2; exit 1 ;; +esac +cli_file=tree-sitter-$cli.gz +sdk_file=wasi-sdk-34.0-$sdk.tar.gz +opt_file=binaryen-version_132-$opt.tar.gz +javascript_file=tree-sitter-javascript-0.23.1.tgz +typescript_file=typescript-5.9.3.tgz +runtime_file=web-tree-sitter-0.27.1.tgz +input_files="$cli_file $sdk_file $opt_file $javascript_file $typescript_file $runtime_file" +# The image the build phase runs in on Linux, with --network none, in CI and from build.sh: node 22.18 on Debian trixie +# (glibc 2.41, which the CLI's binary needs, with gcc and git), pinned by digest. +build_image=node:22.18.0-trixie@sha256:5329a2a013f6a49e8698609f9b20aa9aac670672ab6d88af73e3517cd79790e7 + +url_of() { + case $1 in + "$cli_file") echo "https://github.com/tree-sitter/tree-sitter/releases/download/v0.27.1/$1" ;; + "$sdk_file") echo "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/$1" ;; + "$opt_file") echo "https://github.com/WebAssembly/binaryen/releases/download/version_132/$1" ;; + "$javascript_file") echo "https://registry.npmjs.org/tree-sitter-javascript/-/$1" ;; + "$typescript_file") echo "https://registry.npmjs.org/typescript/-/$1" ;; + "$runtime_file") echo "https://registry.npmjs.org/web-tree-sitter/-/$1" ;; + *) echo "inputs.sh: no source for $1" >&2; exit 1 ;; + esac +} +# The digest a list (inputs.sha256, parsers.sha256) records for a file name, or nothing. +digest_in() { awk -v name="$2" '$2 == name { print $1 }' "$1"; } +sha256() { if command -v sha256sum >/dev/null; then sha256sum "$1"; else shasum -a 256 "$1"; fi | cut -d' ' -f1; } diff --git a/grammars/tree-sitter-typescript/inputs.sha256 b/grammars/tree-sitter-typescript/inputs.sha256 new file mode 100644 index 00000000..d06db181 --- /dev/null +++ b/grammars/tree-sitter-typescript/inputs.sha256 @@ -0,0 +1,15 @@ +46cb97d9a2c52c94e22d9a76c2f1116156b8b61f98360e2a9cce05fcb197cd4d tree-sitter-macos-arm64.gz +b740262cb0f35be64e39b50ad68b020433924a7bcee5ae5c8e40e68d71215647 tree-sitter-macos-x64.gz +d01042f94ba3d6827ddc9788e235f75d8366431be42bdf90ade534d960c98b7d tree-sitter-linux-x64.gz +404be5d54a4955571c4067c21d4699660eab3a534cefb0659341b207f7139ec5 tree-sitter-linux-arm64.gz +9c59398106b417f8f14913380fdf0097a8cc0ff4af9eb3ce0065a859e88d49e9 wasi-sdk-34.0-arm64-macos.tar.gz +87d27fa8adc68dee59bfbf2e22a6d34ef717c34d6bf1d8af2a56fc929d9ce0eb wasi-sdk-34.0-x86_64-macos.tar.gz +b761e3a0721dbae9c09a0059e5fdb2bf917d1b4a8a7b430fb3b5aafb0984b2c4 wasi-sdk-34.0-x86_64-linux.tar.gz +f7e243dff54d60bcc576e94d6166b69f410f2500ae4a9ceef34315be10e77971 wasi-sdk-34.0-arm64-linux.tar.gz +98aad827847af7ef990ed7098d885725c8e5b5aae75073403635617ae4e259aa binaryen-version_132-arm64-macos.tar.gz +40c3de90bb3766bd0282a895e139a6f50253dba49b4f5bb89e66faca162d832e binaryen-version_132-x86_64-macos.tar.gz +195ddc94f9bc89f45abdabb0b9eea86023d727ba90eac8b35b80f2544fc30572 binaryen-version_132-x86_64-linux.tar.gz +c58562417836c5d0493d89bdefc434933bdc097db641b483df86bcfa557a107f binaryen-version_132-aarch64-linux.tar.gz +90e80b25a67517a4daf6ad751557bee21efbda7b7a5a554897933245d1734398 tree-sitter-javascript-0.23.1.tgz +10e108c9cf7d5f2879053dff18515fb405abf2ccef63eaaf017d9c571687a1d3 typescript-5.9.3.tgz +7346db659eb870a5284242851ab7aedea41d7397b8c7e95ff8d9ec5b5a80270f web-tree-sitter-0.27.1.tgz diff --git a/grammars/tree-sitter-typescript/intended-differences.json b/grammars/tree-sitter-typescript/intended-differences.json new file mode 100644 index 00000000..96014f0c --- /dev/null +++ b/grammars/tree-sitter-typescript/intended-differences.json @@ -0,0 +1,104 @@ +{ + "about": "Every difference coherence.patch may make to what tree-sitter-typescript 0.23.2 reads, by construct. compare.mjs parses its corpus with the stock and the patched parsers and fails on any region of difference no entry here allows. An entry allows a region when the region is of its kind (improvement: the stock parser errs there and the patched one does not; regression: the other way about; both err: each errs, differently; reshape: neither errs), in one of its dialects, and overlaps a node its query captures as @construct in the tree of its side. Each entry names its cases, one form to a case, and must show in each of them, in each of its dialects, as that case's one region of difference, so none outlives the patch and a form that breaks fails in its own case. A corpus case no entry names, in any corpus, must read exactly as the stock parsers read it: any region of difference in it fails, whatever an entry's query overlaps; an entry's query alone allows a region only in a file (TypeScript's lib, Coherence's src and mods). A case an improvement names is one of Coherence's (corpus/coherence*.txt, outside the patch) and declares the whole tree the patched parsers must read it as. Keyed by construct and case name, never by byte offset, so the corpus may grow. No entry allows a token renamed: a leaf of the patched trees that is no type of its own spelling, or is named and spelled as one of the stock grammar's tokens, must be read as the stock trees read that spelling somewhere in the corpus, inside an improvement's region as anywhere else. An entry's tokens lists such a reading it brings ({text, type, named}), allowed only inside its own regions, and each must show there.", + "differences": [ + { + "id": "import-type-arguments", + "construct": "an import type with type arguments: import('x').T", + "kind": "improvement", + "dialects": ["typescript", "tsx"], + "side": "patched", + "query": "(member_expression object: [(call_expression function: (import)) (member_expression)] type_arguments: (type_arguments)) @construct", + "cases": [ + "coherence: Coherence: an import type with type arguments in a union", + "coherence: Coherence: an import type with type arguments as an alias's type" + ] + }, + { + "id": "import-type-primary", + "construct": "an import type as a primary type: an array's element, an indexed type's object, keyof's operand, a type argument (import('x').T[], import('x').T['k'], keyof import('x').T, Record)", + "kind": "improvement", + "dialects": ["typescript", "tsx"], + "side": "patched", + "query": "[(array_type (member_expression object: [(call_expression function: (import)) (member_expression)]) @construct) (lookup_type (member_expression object: [(call_expression function: (import)) (member_expression)]) @construct) (index_type_query (member_expression object: [(call_expression function: (import)) (member_expression)]) @construct) (type_arguments (member_expression object: [(call_expression function: (import)) (member_expression)]) @construct)]", + "cases": [ + "coherence: Coherence: an import type as an array's element", + "coherence: Coherence: an import type as keyof's operand", + "coherence: Coherence: an import type with type arguments as an indexed type's object", + "coherence: Coherence: an import type as an array's element in a type argument" + ] + }, + { + "id": "member-named-in", + "construct": "a member named in or instanceof before :, ? or =, or one whose name is in or instanceof and then a digit, _, $ or \\ (in_progress, in$, in2, in\\u0061, instanceof_x), on the line after another member: a property, a class field, a method or a method signature (in?: T, in = 2, in_x(): void, in2(): T, in?(): void, in_progress() {})", + "kind": "improvement", + "dialects": ["typescript", "tsx"], + "side": "patched", + "query": "([(property_signature name: (property_identifier) @construct) (public_field_definition name: (property_identifier) @construct) (method_signature name: (property_identifier) @construct) (method_definition name: (property_identifier) @construct) (abstract_method_signature name: (property_identifier) @construct)] (#match? @construct \"^in(stanceof)?([0-9_$\\\\\\\\]|$)\"))", + "tokens": [{ "text": "instanceof", "type": "property_identifier", "named": true }], + "cases": [ + "coherence: Coherence: a property named in after another member", + "coherence: Coherence: a property named instanceof after another member", + "coherence: Coherence: a property named in_progress after another member", + "coherence: Coherence: a property named instanceof_x after another member", + "coherence: Coherence: a property named in$ after another member", + "coherence: Coherence: a property named in2 after another member", + "coherence: Coherence: a property named in\\u0061 after another member", + "coherence: Coherence: a property named instanceof$ after another member", + "coherence: Coherence: a property named in_x in a type literal after another member", + "coherence: Coherence: a class field named in after another field", + "coherence: Coherence: a method signature named in_x after another member", + "coherence: Coherence: a generic method signature named in2 after another member", + "coherence: Coherence: an optional method signature named in after another member", + "coherence: Coherence: a method named in_progress after a field", + "coherence: Coherence: a method signature named in_x in a declared class after a field" + ] + }, + { + "id": "statement-beginning-with-in", + "construct": "a statement on the line after another that begins with a name that is in or instanceof and then a digit, _, $ or \\ (in_x(), in$.bar(), in2 = 3)", + "kind": "improvement", + "dialects": ["typescript", "tsx"], + "side": "patched", + "query": "((identifier) @construct (#match? @construct \"^in(stanceof)?([0-9_$\\\\\\\\]|$)\"))", + "cases": [ + "coherence: Coherence: a statement beginning with in_x after another", + "coherence: Coherence: a statement beginning with in$ after another" + ] + }, + { + "id": "jsx-text-bare-ampersand", + "construct": "a bare & in JSX text, one that starts no character reference (Billing & Usage, �)", + "kind": "improvement", + "dialects": ["tsx"], + "side": "patched", + "query": "((jsx_text) @construct (#match? @construct \"&\"))", + "cases": [ + "coherence-tsx: Coherence: a bare ampersand in JSX text", + "coherence-tsx: Coherence: a bare ampersand among character references in JSX text", + "coherence-tsx: Coherence: character references at their limits" + ] + }, + { + "id": "jsx-string-bare-ampersand", + "construct": "a bare & in a JSX string, before a letter or the closing quote (to=\"?a=1&b=2\", title='Q&')", + "kind": "improvement", + "dialects": ["tsx"], + "side": "patched", + "query": "(jsx_attribute (string (string_fragment) @construct) (#eq? @construct \"&\"))", + "cases": [ + "coherence-tsx: Coherence: a bare ampersand before a letter in a JSX string", + "coherence-tsx: Coherence: a bare ampersand before a single-quoted JSX string's closing quote", + "coherence-tsx: Coherence: a bare ampersand before a double-quoted JSX string's closing quote" + ] + }, + { + "id": "comparison-after-import-type", + "construct": "a comparison after an import type, which the import type's type arguments now take (x as import('x').T < y), as after any other type and as TypeScript's compiler refuses it", + "kind": "regression", + "dialects": ["typescript", "tsx"], + "side": "stock", + "query": "(binary_expression left: (as_expression (member_expression object: (call_expression function: (import)))) operator: \"<\") @construct", + "cases": ["limits: a comparison after an import type"] + } + ] +} diff --git a/grammars/tree-sitter-typescript/parsers.sha256 b/grammars/tree-sitter-typescript/parsers.sha256 new file mode 100644 index 00000000..f011ba3a --- /dev/null +++ b/grammars/tree-sitter-typescript/parsers.sha256 @@ -0,0 +1,2 @@ +314d255fcf035dccff13108feb79a0193551240870b994777cf4eebad5d0b86b tree-sitter-typescript.wasm +fe56e358812e52df988a2026089650b7ea7d61e9acf0e0f6a1f197c5ab698541 tree-sitter-tsx.wasm diff --git a/mods/coherence/.claude-plugin/plugin.json b/mods/coherence/.claude-plugin/plugin.json index 571660da..8c168976 100644 --- a/mods/coherence/.claude-plugin/plugin.json +++ b/mods/coherence/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "coherence", - "version": "1.10.1", + "version": "1.11.0", "description": "Coherence's hooks through one warm process per session, with its verdicts where the user reads them", "author": { "name": "PostHog" }, "types": "./types/index.d.ts" diff --git a/package-lock.json b/package-lock.json index 7ddf1bd5..33412b3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,23 @@ { "name": "@posthog/coherence", - "version": "1.10.1", + "version": "1.11.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@posthog/coherence", - "version": "1.10.1", + "version": "1.11.0", "license": "MIT", "os": [ "darwin", "linux" ], + "dependencies": { + "web-tree-sitter": "0.27.1" + }, "bin": { - "coherence": "dist/cli.js" + "coherence": "dist/cli.js", + "coherence-statusline": "dist/statusline.js" }, "devDependencies": { "@types/node": "^22.20.3", @@ -1926,6 +1930,12 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/web-tree-sitter": { + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.27.1.tgz", + "integrity": "sha512-qtx0VyUyNRHtL3ze7+v0hCKB/sLcAmY7ZAVp/ZK/bCj0yED8ptvNrr7Vd7DwDyKDWN9baqcUx4uaD2r2ql+6IA==", + "license": "MIT" + }, "node_modules/which": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", diff --git a/package.json b/package.json index 3e28f291..c1584e6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@posthog/coherence", - "version": "1.10.1", + "version": "1.11.0", "description": "A prosthetic for proprioception: specs, invariants, and the readings that keep an agent balanced.", "type": "module", "license": "MIT", @@ -79,5 +79,8 @@ "publishConfig": { "access": "public", "provenance": true + }, + "dependencies": { + "web-tree-sitter": "0.27.1" } } diff --git a/plugins/convex/plugin.json b/plugins/convex/plugin.json index 2cca1226..50c47d81 100644 --- a/plugins/convex/plugin.json +++ b/plugins/convex/plugin.json @@ -1,7 +1,7 @@ { "name": "convex", "version": "0.1.0", - "pluginApi": 2, + "pluginApi": 4, "extends": "typescript", "module": "index.ts", "syntax": { diff --git a/plugins/declared/plugin.json b/plugins/declared/plugin.json index 23be55ae..835e2442 100644 --- a/plugins/declared/plugin.json +++ b/plugins/declared/plugin.json @@ -1,7 +1,7 @@ { "name": "declared", - "version": "1.10.1", - "pluginApi": 2, + "version": "1.11.0", + "pluginApi": 4, "provides": { "declaredLanguages": true }, diff --git a/plugins/go/check.json b/plugins/go/check.json index 8ae6f49e..93b7e96d 100644 --- a/plugins/go/check.json +++ b/plugins/go/check.json @@ -3,8 +3,8 @@ "go.mod": "module shop\n\ngo 1.22\n", "store/secrets.go": "package store\n\n// SecretColumns is the protected thing.\nvar SecretColumns = []string{\"token\"}\n\n// Seal is the chokepoint: the one way a row leaves without its secrets.\nfunc Seal(row map[string]string) map[string]string {\n\tout := map[string]string{}\n\tfor k, v := range row {\n\t\tout[k] = v\n\t}\n\tfor _, column := range SecretColumns {\n\t\tdelete(out, column)\n\t}\n\treturn out\n}\n", "store/rows.go": "package store\n\n// Row is one stored row.\ntype Row map[string]string\n\n// The store's bounds.\nconst (\n\tMaxRows = 100\n\tmaxCols = 8\n)\n", - "api/render.go": "package api\n\nimport \"shop/store\"\n\n// Render seals the row, then reads the secret columns around the seal.\nfunc Render(row map[string]string) int {\n\tsealed := store.Seal(row)\n\treturn len(sealed) + len(store.SecretColumns)\n}\n", - "cmd/shop/main.go": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"shop/api\"\n\t\"shop/store\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/rows\", serveRow)\n\tfmt.Println(http.ListenAndServe(\":8080\", nil))\n}\n\n// serveRow renders the row a request names.\nfunc serveRow(w http.ResponseWriter, r *http.Request) {\n\trow := store.Row{\"id\": r.URL.Path}\n\tfmt.Fprint(w, api.Render(row))\n}\n", + "api/render.go": "package api\n\nimport \"shop/store\"\n\n// Render seals the row, then reads the secret columns around the seal.\nfunc Render(row store.Row) int {\n\tsealed := store.Seal(row)\n\treturn len(sealed) + len(store.SecretColumns)\n}\n", + "cmd/shop/main.go": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"shop/api\"\n\tst \"shop/store\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/rows\", serveRow)\n\tfmt.Println(http.ListenAndServe(\":8080\", nil))\n}\n\n// serveRow renders the row a request names.\nfunc serveRow(w http.ResponseWriter, r *http.Request) {\n\trow := st.Row{\"id\": r.URL.Path}\n\tfmt.Fprint(w, api.Render(row))\n}\n", "store/secrets_test.go": "package store\n\nimport \"testing\"\n\nfunc TestColumns(t *testing.T) {\n\tif len(SecretColumns) == 0 {\n\t\tt.Fatal(\"no secret columns\")\n\t}\n}\n", "README.md": "# A module\n" }, @@ -84,21 +84,29 @@ "file": "api/render.go", "module": "store/secrets.go", "names": [ - "*" + "Seal", + "SecretColumns" ] }, { "file": "cmd/shop/main.go", "module": "api/render.go", "names": [ - "*" + "Render" ] }, { "file": "cmd/shop/main.go", "module": "store/rows.go", "names": [ - "*" + "Row" + ] + }, + { + "file": "api/render.go", + "module": "store/rows.go", + "names": [ + "Row" ] } ], @@ -107,6 +115,7 @@ "from": "api", "to": "store", "symbols": [ + "Row", "Seal", "SecretColumns" ] @@ -138,5 +147,19 @@ "rule": "http route" } ] + }, + "reference": { + "files": { + "secrets": "store/secrets.go", + "rows": "store/rows.go", + "render": "api/render.go", + "main": "cmd/shop/main.go" + }, + "names": { + "SECRET_COLUMNS": "SecretColumns", + "seal": "Seal", + "Row": "Row", + "render": "Render" + } } } diff --git a/plugins/go/go-entrances.ts b/plugins/go/go-entrances.ts index 1184460b..6dbc2893 100644 --- a/plugins/go/go-entrances.ts +++ b/plugins/go/go-entrances.ts @@ -7,7 +7,7 @@ import { posix } from "node:path"; import { handlerName, languageOfFile, throughOf, type EntranceCandidate, type EntranceSyntax } from "../../src/plugins/api.ts"; -import { codeOnly, declarationsIn, importsIn, packageClause, uncommented } from "./go-source.ts"; +import { codeOnly, packageClause, uncommented } from "./go-source.ts"; /** A registration on a ServeMux: `mux.HandleFunc(`, `http.Handle(`, with a string pattern first. */ const SERVE_MUX = /\b[A-Za-z_]\w*\s*\.\s*(HandleFunc|Handle)\s*\(\s*("(?:[^"\\\n]|\\.)*"|`[^`]*`)\s*,/g; @@ -52,6 +52,18 @@ function goHandlerName(expression: string): string { return /([A-Za-z_]\w*)\s*\(\s*\)\s*$/.exec(e)?.[1] ?? ""; } +/** Each package-level func of the code-only text, by name, with its one-based line: `func main(`, `func Map[K any](`; a method's receiver comes before its name, so a method is none. */ +function funcsIn(code: string): { name: string; line: number }[] { + return [...code.matchAll(/^func[ \t]+([A-Za-z_]\w*)[ \t]*[[(]/gm)].map((m) => ({ name: m[1]!, line: lineAt(code, m.index) })); +} + +/** Whether the file imports one of the routers: a quoted path of one in its imports, which Go puts before any other declaration, so the text before the first is read. */ +function importsRouter(text: string, code: string): boolean { + const first = /^(?:func|type|var|const)\b/m.exec(code); + const imports = text.slice(0, first === null ? text.length : first.index); + return [...imports.matchAll(/"((?:[^"\\\n]|\\.)*)"|`([^`]*)`/g)].some((m) => ROUTERS.test(m[1] ?? m[2] ?? "")); +} + /** The one-based line of a character offset in the text. */ function lineAt(text: string, index: number): number { let line = 1; @@ -68,9 +80,9 @@ function goCandidates(file: string, original: string, wrappers: readonly string[ const through = throughOf(span, text, wrappers, GO_ENTRANCES); out.push(through === undefined ? c : { ...c, through }); }; - const declarations = declarationsIn(original); + const funcs = funcsIn(code); if (packageClause(text) === "main") { - const main = declarations.find((d) => d.form === "func" && d.names[0] === "main"); + const main = funcs.find((d) => d.name === "main"); if (main !== undefined) { const folder = posix.dirname(file); const command = folder === "." ? undefined : posix.basename(folder); @@ -92,15 +104,14 @@ function goCandidates(file: string, original: string, wrappers: readonly string[ } }; register(SERVE_MUX, "http route", (method, path, handler) => `${method}("${path}") registers ${handler} on a ServeMux`, (path) => PATTERN.test(path)); - if (importsIn(original).some((spec) => ROUTERS.test(spec.path))) { + if (importsRouter(text, code)) { register(ROUTER_METHOD, "router route", (method, path, handler) => `a router's ${method}("${path}") is handled by ${handler}`, (path) => path === "" || path.startsWith("/")); } // A cgo export: `//export Name` directly above func Name, which C calls by that name. const lines = original.split("\n"); - for (const d of declarations) { - if (d.form !== "func") continue; + for (const d of funcs) { const above = lines[d.line - 2]?.replace(/\r$/, ""); - if (above !== undefined && new RegExp(`^//export\\s+${d.names[0]}\\s*$`).test(above)) add({ file, line: d.line, symbol: d.names[0]!, rule: "cgo export", why: `${d.names[0]} carries //export: C code calls it by that name` }, ""); + if (above !== undefined && new RegExp(`^//export\\s+${d.name}\\s*$`).test(above)) add({ file, line: d.line, symbol: d.name, rule: "cgo export", why: `${d.name} carries //export: C code calls it by that name` }, ""); } return out; } diff --git a/plugins/go/go-interfaces.ts b/plugins/go/go-interfaces.ts deleted file mode 100644 index d553d1c2..00000000 --- a/plugins/go/go-interfaces.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Go's facts for the interface map: what a declaration line's keyword says - * can execute (interfaces.ts reads them through the declares slot). - */ - -import type { InterfaceSymbol } from "../../src/plugins/api.ts"; -import { declarationAt } from "./go-source.ts"; - -/** - * A func has a body, and so does a struct or any other defined type, whose - * methods are declared apart from it (as a Rust struct's impl blocks are); - * an interface or a type alias declares a type; a const is a value; a var - * is read by what it is set to: a func literal is a body, a basic literal - * or nil a value, anything else (a call's result, no value at all, set - * later) may hold a func, so it is counted as able to execute. - */ -export function goDeclares(line: string): InterfaceSymbol["declares"] { - const declared = declarationAt(line); - if (declared === undefined) return "unknown"; - if (declared.form === "alias" || declared.form === "interface") return "type"; - if (declared.form === "const") return "value"; - if (declared.form === "var") { - if (/^func\b/.test(declared.value)) return "body"; - if (/^(?:[\d"'`.-]|true\b|false\b|nil\b)/.test(declared.value)) return "value"; - return "unknown"; - } - return "body"; -} diff --git a/plugins/go/go-scope.ts b/plugins/go/go-scope.ts deleted file mode 100644 index ced5fd1e..00000000 --- a/plugins/go/go-scope.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Go's facts for the component interface reading: which declaration lines - * declare a type only, and what the word index reads of a file's imports - * (component-interfaces.ts reads them through the interfaces slot, - * kept-answers.ts through the same wildcardModules). - */ - -import type { InterfaceSyntax } from "../../src/plugins/api.ts"; -import { declarationAt } from "./go-source.ts"; - -/** - * An interface or a type alias declares a type only; a struct or another - * defined type carries methods, so a reach goes on through it. Go has no - * default export. gopls reads its module whole, so it takes no bounds. - * - * Go renames packages, never names: `st "shop/store"` binds the package as - * st, and every use still spells the member's own name (`st.Seal`), so no - * import list extends a name to an alias. A dot import (`import . - * "shop/store"`) brings the package's names in unqualified, and each use - * still spells the name, which the word index reads like any other token; - * gopls reports no site at the import itself, so the reading needs no - * module named for it (and from a file's path alone, with no root to read - * the go.mod by, the package's files could not be named). - */ -export const GO_INTERFACES: InterfaceSyntax = { - isTypeDeclaration(line) { - const form = declarationAt(line)?.form; - return form === "alias" || form === "interface"; - }, - isDefaultExport: () => false, - serverBounds: false, - importLists: () => [], - defaultNames: () => [], - wildcardModules: () => [], -}; diff --git a/plugins/go/go-source.ts b/plugins/go/go-source.ts index a56269f0..6eb50244 100644 --- a/plugins/go/go-source.ts +++ b/plugins/go/go-source.ts @@ -1,25 +1,19 @@ /** - * Go's facts for the plain source scan: which names a file declares at its - * package level, which packages it imports and which of their names it - * uses, and where an import path resolves (source.ts reads them through the - * source slot). + * Where a Go import leads, and what the plugin's other readings read of Go's + * text: what no parse can say, since a package's place is Go's module + * layout, not its syntax. What a file declares, imports and uses through an + * import is read through Go's parser and go.scm (the manifest's treeSitter). * * A path resolves by the module layout, not by gopls: the nearest go.mod * above the importing file names its module path, and a path under it is * the folder below that go.mod; a go.work at the root adds the modules it * uses. A replace directive and a path into any other module (the standard * library, a dependency, a vendored copy) resolve to nothing. - * - * This file is the plugin's one model of Go: what code is (comments and - * literals set apart, a raw string across lines included), what a - * declaration is (alone or in a grouped `var (`, `const (`, `type (` - * block), what an import is and what makes a name exported. The other - * files read Go through it. */ import { readdirSync, readFileSync, statSync } from "node:fs"; import { posix, resolve } from "node:path"; -import type { SourceSyntax } from "../../src/plugins/api.ts"; +import type { ModuleResolution } from "../../src/plugins/api.ts"; /** Whether a Go identifier is exported: its first character is an upper-case letter. */ export function exported(name: string): boolean { @@ -110,211 +104,8 @@ export function codeOnly(text: string): string { return text.split("\n").map((line) => blankLine(line, state, true)).join("\n"); } -/* ----------------------------------------------------------- declarations */ - -/** What a declaration's keyword and shape say it is. */ -export type GoForm = "func" | "alias" | "interface" | "struct" | "defined" | "const" | "var"; - -/** A package-level declaration, read the one way every Go reading reads one. */ -export interface GoDeclaration { - /** The names it declares, in order, the blank identifier left out: `var a, b int` declares two. */ - names: string[]; - keyword: "func" | "type" | "var" | "const"; - form: GoForm; - /** Whether its first name is exported. */ - exported: boolean; - /** For a var: the text after `=`, trimmed; empty when it has none. */ - value: string; - /** Inside a grouped block, one level in. */ - grouped: boolean; -} - -const IDENT = "[A-Za-z_][A-Za-z0-9_]*"; -const NAMES = new RegExp(`^(${IDENT}(?:\\s*,\\s*${IDENT})*)`); - -/** The type's form from the text after its name: `= T` an alias, `interface` or `struct`, else a defined type; type parameters (`[T any]`) are passed over, an array type (`[4]int`) is not one. */ -function typeForm(rest: string): GoForm { - let after = rest.trimStart(); - const params = /^\[\s*[A-Za-z_]\w*\s+[^\]]/.exec(after); - if (params !== null) { - let depth = 0; - let i = 0; - for (; i < after.length; i++) { - if (after[i] === "[") depth += 1; - else if (after[i] === "]" && --depth === 0) break; - } - after = after.slice(i + 1).trimStart(); - } - if (after.startsWith("=")) return "alias"; - if (/^interface\b/.test(after)) return "interface"; - if (/^struct\b/.test(after)) return "struct"; - return "defined"; -} - -/** A declaration of `keyword` whose names start the code text. */ -function declarationFrom(keyword: "type" | "var" | "const", code: string, grouped: boolean): GoDeclaration | undefined { - const m = NAMES.exec(code); - if (m === null) return undefined; - const names = m[1]!.split(/\s*,\s*/).filter((n) => n !== "_"); - if (names.length === 0) return undefined; - const rest = code.slice(m[0].length); - const form: GoForm = keyword === "type" ? typeForm(rest) : keyword; - const value = keyword === "var" ? (/=\s*(.*)$/.exec(rest)?.[1]?.trim() ?? "") : ""; - return { names, keyword, form, exported: exported(names[0]!), value, grouped }; -} - -/** The net count of opening brackets over closing ones in a code-only line. */ -function depthChange(code: string): number { - let depth = 0; - for (const c of code) { - if (c === "(" || c === "[" || c === "{") depth += 1; - else if (c === ")" || c === "]" || c === "}") depth -= 1; - } - return depth; -} - -/** - * Reads a file's lines in order and says what each declares at the package - * level. It carries what a line alone cannot say: a raw string or block - * comment opened above, and whether the line sits in a grouped block (and - * at which bracket depth, so a member's multi-line value or a struct's - * fields are never members). A package clause starts a file afresh. - */ -export class GoReader { - private lexical: Lexical = { raw: false, block: false }; - private group: "type" | "var" | "const" | undefined; - private depth = 0; - - /** What the line declares, or undefined. */ - feed(raw: string): GoDeclaration | undefined { - const line = raw.replace(/\r$/, ""); - if (/^package\s+[A-Za-z_]\w*\s*(?:\/\/.*)?$/.test(line)) { - this.lexical = { raw: false, block: false }; - this.group = undefined; - this.depth = 0; - return undefined; - } - const inside = this.lexical.raw || this.lexical.block; - const code = blankLine(line, this.lexical, true); - if (inside) { - if (this.group !== undefined) this.close(code); - return undefined; - } - if (this.group !== undefined) { - // A line at column zero that begins a new statement ends a block left open (a file cut short). - if (/^[A-Za-z_]/.test(code)) { - this.group = undefined; - this.depth = 0; - } else { - const at = this.depth; - const keyword = this.group; - this.close(code); - return at === 1 && /^\s+[A-Za-z_]/.test(code) ? declarationFrom(keyword, code.trimStart(), true) : undefined; - } - } - const func = new RegExp(`^func\\s+(${IDENT})\\s*[\\[(]`).exec(code); - if (func !== null) return func[1] === "_" ? undefined : { names: [func[1]!], keyword: "func", form: "func", exported: exported(func[1]!), value: "", grouped: false }; - const opens = /^(type|var|const)\s*\(/.exec(code); - if (opens !== null) { - this.depth = depthChange(code.slice(opens[0].length - 1)); - if (this.depth > 0) this.group = opens[1] as "type" | "var" | "const"; - return undefined; - } - const single = /^(type|var|const)\s+/.exec(code); - return single === null ? undefined : declarationFrom(single[1] as "type" | "var" | "const", code.slice(single[0].length), false); - } - - /** Carries the block's bracket depth past a line, ending it when the depth comes back to zero. */ - private close(code: string): void { - this.depth += depthChange(code); - if (this.depth <= 0) { - this.group = undefined; - this.depth = 0; - } - } -} - -/** Every package-level declaration of a file's text, with its one-based line. */ -export function declarationsIn(text: string): (GoDeclaration & { line: number })[] { - const reader = new GoReader(); - const found: (GoDeclaration & { line: number })[] = []; - text.split("\n").forEach((line, i) => { - const declared = reader.feed(line); - if (declared !== undefined) found.push({ ...declared, line: i + 1 }); - }); - return found; -} - -/** - * The declarations the source slot read last, by the line's text: a grouped - * member's line (`\tLimit = 3`) does not say alone whether it is a var, a - * const or a type, so the interfaces and declares slots, asked of a line - * the scan read just before, read the answer it gave. Kept small: cleared - * past a bound, never a store. - */ -const MEMBERS = new Map(); -const MEMBERS_BOUND = 20_000; - -/** - * What one line declares, read the one way every Go reading reads it: a - * column-zero line alone, a grouped member through what the source scan - * read of it. - */ -export function declarationAt(line: string): GoDeclaration | undefined { - const text = line.replace(/\r$/, ""); - if (/^\s/.test(text)) return MEMBERS.get(text); - return new GoReader().feed(text); -} - -/** The reader the source slot feeds: declarationsOf hands it every line of one file in order, and the package clause each file opens with starts it afresh. */ -const STREAM = new GoReader(); - /* ----------------------------------------------------------------- imports */ -/** One import spec: the path, and the name it is bound to when the spec gives one (an identifier, `_` or `.`). */ -export interface GoImport { - path: string; - alias?: string; - /** One-based. */ - line: number; -} - -const SPEC = /^\s*(?:([A-Za-z_]\w*|\.)\s+)?(?:"((?:[^"\\]|\\.)*)"|`([^`]*)`)/; - -/** Every import spec of the text, single (`import "fmt"`) and grouped (`import (` … `)`), named, dot and blank. */ -export function importsIn(text: string): GoImport[] { - const lines = uncommented(text).split("\n"); - const out: GoImport[] = []; - const take = (spec: string, line: number): void => { - const m = SPEC.exec(spec); - if (m === null) return; - const path = m[2] ?? m[3] ?? ""; - if (path === "") return; - out.push(m[1] === undefined ? { path, line } : { path, alias: m[1], line }); - }; - for (let i = 0; i < lines.length; i++) { - const line = lines[i]!; - const group = /^import\s*\((.*)$/.exec(line); - if (group !== null) { - // A spec may share the opening line, and several may share one line, split by semicolons. - let rest = group[1]!; - let j = i; - for (;;) { - const close = rest.indexOf(")"); - for (const spec of (close < 0 ? rest : rest.slice(0, close)).split(";")) take(spec, j + 1); - if (close >= 0 || j + 1 >= lines.length) break; - j += 1; - rest = lines[j]!; - } - i = j; - continue; - } - const single = /^import\s+(.*)$/.exec(line); - if (single !== null) take(single[1]!, i + 1); - } - return out; -} - /** The name a package is referred to by when its import gives none: its path's last element, a major version (`/v2`, `.v3`) passed over. */ export function packageNameOf(path: string): string { const parts = path.split("/"); @@ -323,20 +114,6 @@ export function packageNameOf(path: string): string { return last.replace(/\.v\d+$/, "").replace(/^go-/, "").replace(/[^A-Za-z0-9_].*$/, ""); } -/** Every `x.Name` the code spells, by x: a qualified identifier names an imported package's member this way. */ -export function selectorsIn(text: string): Map> { - const out = new Map>(); - for (const m of codeOnly(text).matchAll(/(?(); - names.add(m[2]!); - out.set(m[1]!, names); - } - return out; -} - -/** Separates an import path from the name a specifier asks for; `#` is never in a Go import path. */ -const NAMED = "#"; - /* -------------------------------------------------------------- packages */ /** A file's text, or undefined when it cannot be read. */ @@ -458,69 +235,26 @@ export function packageFiles(root: string, folder: string): string[] { } } -/** The names each file declares, read once per file and again when it changes. */ -const DECLARED = new Map }>(); - -function declaredIn(root: string, file: string): Set { - const path = resolve(root, file); - let at: number; - try { - at = statSync(path).mtimeMs; - } catch { - return new Set(); - } - const known = DECLARED.get(path); - if (known !== undefined && known.at === at) return known.names; - const names = new Set(declarationsIn(textOf(path) ?? "").flatMap((d) => d.names)); - DECLARED.set(path, { at, names }); - return names; -} - /** - * A Go import is of a package, a folder of files: importsOf hands the path - * once per exported name the file uses through it (`path#Name`), so each - * resolves to the file of the package that declares that name, and the - * closure's hop out is confirmed by a use of that file's names; a package - * imported for its side effects, dot-imported, or whose names the file - * never spells is handed whole and resolves to its first file in sorted - * order. A file of the package the change deleted (vanished) stands in for - * a name no file left declares, and for the package whole, so its - * importers are found. + * A Go import is of a package, a folder of files: resolveModule names the + * package as a module, its folder and every file of it, and the import + * brings in each exported name the file uses through the name it binds + * (st.Seal: boundName, the alias the spec gives taking its place), so the + * core joins each name to the file that declares it (economy/source.ts + * importsOf). A package imported for its side effects, dot-imported, or + * whose names the file never spells is imported whole, and reaches every + * file of it. A file of the package the change deleted (vanished) stays + * among its files, so its importers are found. Go has no glob import the + * word index keys by a path: a dot import's names are spelled at each use. */ -export const GO_SOURCE: SourceSyntax = { - declarationOf(line) { - const declared = STREAM.feed(line); - if (declared === undefined) return undefined; - if (declared.grouped) { - if (MEMBERS.size >= MEMBERS_BOUND) MEMBERS.clear(); - MEMBERS.set(line.replace(/\r$/, ""), declared); - } - return { name: declared.names[0]!, exported: declared.exported }; - }, +export const GO_RESOLVE: ModuleResolution = { resolveModule(root, from, specifier, vanished) { - const at = specifier.indexOf(NAMED); - const path = at < 0 ? specifier : specifier.slice(0, at); - const name = at < 0 ? undefined : specifier.slice(at + 1); - const folder = packageFolderOf(root, from, path); + const folder = packageFolderOf(root, from, specifier); if (folder === undefined) return undefined; const present = packageFiles(root, folder); - const gone = [...vanished].filter((f) => isPackageFile(f) && (posix.dirname(f) === "." ? "" : posix.dirname(f)) === folder && !present.includes(f)).sort(); - if (name !== undefined) { - const declaring = present.find((file) => declaredIn(root, file).has(name)); - if (declaring !== undefined) return declaring; - } - return gone[0] ?? present[0]; - }, - importsOf(text, add) { - const selectors = selectorsIn(text); - for (const spec of importsIn(text)) { - if (spec.alias === "_" || spec.alias === ".") { - add(undefined, spec.path); - continue; - } - const used = [...(selectors.get(spec.alias ?? packageNameOf(spec.path)) ?? [])].filter(exported).sort(); - if (used.length === 0) add(undefined, spec.path); - for (const name of used) add(undefined, `${spec.path}${NAMED}${name}`); - } + const gone = [...vanished].filter((f) => isPackageFile(f) && (posix.dirname(f) === "." ? "" : posix.dirname(f)) === folder && !present.includes(f)); + return { module: folder, files: [...present, ...gone].sort() }; }, + modulePaths: () => [], + boundName: packageNameOf, }; diff --git a/plugins/go/go-top-level.ts b/plugins/go/go-top-level.ts deleted file mode 100644 index a3aabe7f..00000000 --- a/plugins/go/go-top-level.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * What the spec model asks of a Go file: whether its top level declares a - * name. A package-level func, type, var or const, written alone - * (`func Write(`, `type Entry struct`) or inside a grouped declaration - * (`var (` … `)`), each name of a list (`var a, b int`) among them. A method - * (`func (e *Entry) Name(`) is not a package-level name, and neither is a - * local inside a function body, a struct's field or a name in a comment or - * a raw string. Read through go-source.ts, the plugin's one model of Go. - */ - -import { declarationsIn } from "./go-source.ts"; - -const IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/; - -/** Whether the text declares the name at its top level. */ -export function goDeclaresAtTop(text: string, name: string): boolean { - if (!IDENT.test(name)) return false; - return declarationsIn(text).some((d) => d.names.includes(name)); -} diff --git a/plugins/go/go.scm b/plugins/go/go.scm new file mode 100644 index 00000000..7ae31dcc --- /dev/null +++ b/plugins/go/go.scm @@ -0,0 +1,47 @@ +; Go's imports, the package names a file uses through them, and its package-level declarations, as the capture names Coherence reads (docs/plugins.md). +; The parser beside it, tree-sitter-go.wasm, is the one the tree-sitter-go 0.25.0 npm package ships, copied as is (language ABI 15). + +; import st "shop/store", import . "shop/store", import _ "shop/store" -- the whole package, bound to the name the spec gives it: +; a dot or a blank binds none, so no use is read through it (a local named as the package is no qualifier of it). +; A spec alone is its statement; a spec of an import ( ... ) block is one statement inside the block. +(import_declaration (import_spec name: [(package_identifier) (dot) (blank_identifier)] @import.alias path: [(interpreted_string_literal (interpreted_string_literal_content) @import.module) (raw_string_literal (raw_string_literal_content) @import.module)])) @import +(import_spec_list (import_spec name: [(package_identifier) (dot) (blank_identifier)] @import.alias path: [(interpreted_string_literal (interpreted_string_literal_content) @import.module) (raw_string_literal (raw_string_literal_content) @import.module)]) @import) + +; import "shop/store" -- the whole package, bound to its own name (the resolution's boundName) +(import_declaration (import_spec !name path: [(interpreted_string_literal (interpreted_string_literal_content) @import.module) (raw_string_literal (raw_string_literal_content) @import.module)])) @import +(import_spec_list (import_spec !name path: [(interpreted_string_literal (interpreted_string_literal_content) @import.module) (raw_string_literal (raw_string_literal_content) @import.module)]) @import) + +; st.Seal(row), store.Row{}, func(r store.Row) -- an exported name used through a package's name, which says which of its names an import brings in; +; a name starting lower case is never one, and a predicate's pattern has no Unicode classes, so a name starting with any other letter is let through +; (Go refuses an unexported one from outside its package, so through an import it is never written) +((selector_expression operand: (identifier) @use.qualifier field: (field_identifier) @use.name) (#not-match? @use.name "^[a-z_]")) +((qualified_type package: (package_identifier) @use.qualifier name: (type_identifier) @use.name) (#not-match? @use.name "^[a-z_]")) + +; a func at the package level declares a body; a method (func (r Row) Name()) is its type's, no name of the package's +((source_file (function_declaration name: (identifier) @name) @declaration.body) (#not-eq? @name "_")) + +; an interface or an alias declares a type; a struct or any other defined type a body, since its methods are declared apart from it +((source_file (type_declaration (type_spec name: (type_identifier) @name type: (interface_type)) @declaration.type)) (#not-eq? @name "_")) +((source_file (type_declaration (type_alias name: (type_identifier) @name) @declaration.type)) (#not-eq? @name "_")) +((source_file (type_declaration (type_spec name: (type_identifier) @name type: [(type_identifier) (generic_type) (qualified_type) (pointer_type) (struct_type) (array_type) (slice_type) (map_type) (channel_type) (function_type) (negated_type) (parenthesized_type)]) @declaration.body)) (#not-eq? @name "_")) + +; a const, alone or in a const ( ... ) block, each name of a list (const A, B = 1, 2) among them, declares a value; +; the names are the spec's own identifiers, since tree-sitter-go puts a list's commas in its name field and a field match reads only the first name +((source_file (const_declaration (const_spec (identifier) @name) @declaration.value)) (#not-eq? @name "_")) + +; a var is read by its first value: a func literal is a body; a literal, or an operator's result (no operator yields a func), a value; +; anything else (a call's result, a name, a composite that may hold a func, no value at all) may hold a func, so it is counted as able to execute +((source_file (var_declaration [ + (var_spec name: (identifier) @name value: (expression_list . (func_literal))) + (var_spec_list (var_spec name: (identifier) @name value: (expression_list . (func_literal)))) +] @declaration.body)) (#not-eq? @name "_")) +((source_file (var_declaration [ + (var_spec name: (identifier) @name value: (expression_list . [(int_literal) (float_literal) (imaginary_literal) (rune_literal) (interpreted_string_literal) (raw_string_literal) (nil) (true) (false) (iota) (binary_expression) (unary_expression operator: ["-" "+" "!" "^"])])) + (var_spec_list (var_spec name: (identifier) @name value: (expression_list . [(int_literal) (float_literal) (imaginary_literal) (rune_literal) (interpreted_string_literal) (raw_string_literal) (nil) (true) (false) (iota) (binary_expression) (unary_expression operator: ["-" "+" "!" "^"])]))) +] @declaration.value)) (#not-eq? @name "_")) +((source_file (var_declaration [ + (var_spec name: (identifier) @name !value) + (var_spec_list (var_spec name: (identifier) @name !value)) + (var_spec name: (identifier) @name value: (expression_list . [(identifier) (selector_expression) (index_expression) (slice_expression) (call_expression) (type_assertion_expression) (type_conversion_expression) (type_instantiation_expression) (composite_literal) (parenthesized_expression) (unary_expression operator: ["*" "&" "<-"])])) + (var_spec_list (var_spec name: (identifier) @name value: (expression_list . [(identifier) (selector_expression) (index_expression) (slice_expression) (call_expression) (type_assertion_expression) (type_conversion_expression) (type_instantiation_expression) (composite_literal) (parenthesized_expression) (unary_expression operator: ["*" "&" "<-"])]))) +] @declaration.unknown)) (#not-eq? @name "_")) diff --git a/plugins/go/go.ts b/plugins/go/go.ts index 917037e9..85b7b11e 100644 --- a/plugins/go/go.ts +++ b/plugins/go/go.ts @@ -44,6 +44,7 @@ import { type Definition, type Ladder, type LanguageAdapter, + type ServerSymbol, type Position, type Range, type ReferenceSite, @@ -72,12 +73,15 @@ interface DocumentSymbol { range: Range; selectionRange: Range; children?: DocumentSymbol[]; + /** Set where the server answered a flat SymbolInformation list naming the symbol's container: no top-level symbol. */ + nested?: true; } interface SymbolInformation { name: string; kind: number; location: { uri: string; range: Range }; + containerName?: string; } interface Location { @@ -253,6 +257,11 @@ export class GoAdapter implements LanguageAdapter { }; } + /** The file's top-level symbols as the server reports them: the independent account plugin check and plugin calibrate hold the text readings to. */ + async topLevelSymbols(file: string): Promise { + return (await this.documentSymbols(file)).filter((s) => s.nested !== true).map((s) => ({ name: s.name, line: s.selectionRange.start.line + 1, kind: s.kind })); + } + private async documentSymbols(file: string): Promise { const cached = this.symbolCache.get(file); if (cached !== undefined) return cached; @@ -262,7 +271,7 @@ export class GoAdapter implements LanguageAdapter { } const client = await this.live(); const result = await client.request("textDocument/documentSymbol", { textDocument: { uri: this.uri(file) } }); - const symbols: DocumentSymbol[] = (result ?? []).map((s) => ("location" in s ? { name: s.name, kind: s.kind, range: s.location.range, selectionRange: s.location.range } : s)); + const symbols: DocumentSymbol[] = (result ?? []).map((s) => ("location" in s ? { name: s.name, kind: s.kind, range: s.location.range, selectionRange: s.location.range, ...(s.containerName ? { nested: true as const } : {}) } : s)); this.symbolCache.set(file, symbols); return symbols; } diff --git a/plugins/go/plugin.json b/plugins/go/plugin.json index 53125bc5..49d97d77 100644 --- a/plugins/go/plugin.json +++ b/plugins/go/plugin.json @@ -1,7 +1,7 @@ { "name": "go", "version": "0.1.0", - "pluginApi": 2, + "pluginApi": 4, "provides": { "language": "go" }, @@ -23,12 +23,14 @@ "vendor" ], "module": "index.ts", + "treeSitter": { + "parser": "tree-sitter-go.wasm", + "queries": "go.scm", + "resolve": "go-source.ts#GO_RESOLVE", + "privateName": "^\\P{Lu}" + }, "syntax": { - "entrances": "go-entrances.ts#GO_ENTRANCES", - "interfaces": "go-scope.ts#GO_INTERFACES", - "source": "go-source.ts#GO_SOURCE", - "declares": "go-interfaces.ts#goDeclares", - "topLevel": "go-top-level.ts#goDeclaresAtTop" + "entrances": "go-entrances.ts#GO_ENTRANCES" }, "ladder": { "top": "visibility-choked", diff --git a/plugins/go/tree-sitter-go.wasm b/plugins/go/tree-sitter-go.wasm new file mode 100644 index 00000000..71a01bd8 Binary files /dev/null and b/plugins/go/tree-sitter-go.wasm differ diff --git a/plugins/python/check.json b/plugins/python/check.json index f6394703..2ced85fa 100644 --- a/plugins/python/check.json +++ b/plugins/python/check.json @@ -5,16 +5,18 @@ "shop/store/__init__.py": "", "shop/store/secrets.py": "SECRET_COLUMNS = {\"tokens\": [\"token\"]}\n\n\ndef seal(pattern, row):\n out = dict(row)\n for column in SECRET_COLUMNS.get(pattern, []):\n out.pop(column, None)\n return out\n", "shop/api/__init__.py": "", - "shop/api/render.py": "from shop.store.secrets import SECRET_COLUMNS, seal\n\n\ndef render(pattern, row):\n sealed = seal(pattern, row)\n leaked = SECRET_COLUMNS.get(pattern)\n return {\"sealed\": sealed, \"leaked\": leaked}\n", + "shop/api/render.py": "import shop.store.secrets\nfrom shop.store.secrets import (\n SECRET_COLUMNS,\n seal as sealed,\n)\nfrom shop.store import *\nfrom shop.store.rows import Row\n\n\ndef render(pattern, row):\n from shop.store.secrets import seal\n\n sealed_row = sealed(pattern, Row(row))\n leaked = SECRET_COLUMNS.get(pattern)\n return {\"sealed\": sealed_row, \"leaked\": leaked, \"again\": seal(pattern, row)}\n", "tests/test_secrets.py": "from shop.store.secrets import SECRET_COLUMNS\n\n\ndef test_columns():\n assert SECRET_COLUMNS\n", "README.md": "# A project\n", - "shop/api/app.py": "from shop.api.render import render\n\n\nclass App:\n def get(self, path):\n def wrap(fn):\n return fn\n\n return wrap\n\n\napp = App()\n\n\n@app.get(\"/rows\")\ndef rows(row):\n return render(\"tokens\", row)\n" + "shop/api/app.py": "from shop.api.render import render\n\n\nclass App:\n def get(self, path):\n def wrap(fn):\n return fn\n\n return wrap\n\n\napp = App()\n\n\n@app.get(\"/rows\")\ndef rows(row):\n return render(\"tokens\", row)\n", + "shop/store/rows.py": "class Row(dict):\n \"\"\"One stored row, by column.\"\"\"\n" }, "language": { "files": [ "shop/store/secrets.py", "shop/api/render.py", - "shop/stubs.pyi" + "shop/stubs.pyi", + "shop/store/rows.py" ], "not": [ "README.md", @@ -47,16 +49,16 @@ "protects": "SECRET_COLUMNS", "chokepoint": "seal", "references": [ - "shop/api/render.py:1", - "shop/api/render.py:6", + "shop/api/render.py:3", + "shop/api/render.py:14", "shop/store/secrets.py:6", "tests/test_secrets.py:1", "tests/test_secrets.py:5" ], "grade": "broken", "bypasses": [ - "shop/api/render.py:1", - "shop/api/render.py:6" + "shop/api/render.py:3", + "shop/api/render.py:14" ], "readings": { "declared": { @@ -73,6 +75,9 @@ "shop/store/secrets.py": [ "SECRET_COLUMNS", "seal" + ], + "shop/store/rows.py": [ + "Row" ] }, "imports": [ @@ -87,9 +92,17 @@ "file": "shop/api/render.py", "module": "shop/store/secrets.py", "names": [ + "*", "SECRET_COLUMNS", "seal" ] + }, + { + "file": "shop/api/render.py", + "module": "shop/store/rows.py", + "names": [ + "Row" + ] } ], "interfaces": [ @@ -97,6 +110,7 @@ "from": "shop/api", "to": "shop/store", "symbols": [ + "Row", "SECRET_COLUMNS", "seal" ] @@ -109,5 +123,19 @@ "rule": "route decorator" } ] + }, + "reference": { + "files": { + "secrets": "shop/store/secrets.py", + "rows": "shop/store/rows.py", + "render": "shop/api/render.py", + "main": "shop/api/app.py" + }, + "names": { + "SECRET_COLUMNS": "SECRET_COLUMNS", + "seal": "seal", + "Row": "Row", + "render": "render" + } } } diff --git a/plugins/python/plugin.json b/plugins/python/plugin.json index 1ab82d39..f93ef73b 100644 --- a/plugins/python/plugin.json +++ b/plugins/python/plugin.json @@ -1,7 +1,7 @@ { "name": "python", - "version": "1.10.1", - "pluginApi": 2, + "version": "1.11.0", + "pluginApi": 4, "provides": { "language": "python" }, @@ -116,12 +116,15 @@ "whenVacuous": "convention" }, "module": "index.ts", + "treeSitter": { + "parser": "tree-sitter-python.wasm", + "queries": "python.scm", + "resolve": "python-source.ts#PYTHON_RESOLVE", + "privateName": "^_" + }, "syntax": { "entrances": "python-entrances.ts#PYTHON_ENTRANCES", "interfaces": "python-scope.ts#PYTHON_INTERFACES", - "source": "python-source.ts#PYTHON_SOURCE", - "declares": "python-interfaces.ts#pythonDeclares", - "topLevel": "python-top-level.ts#pythonDeclaresAtTop", "boundaries": "tach-boundaries.ts#TACH_BOUNDARIES" } } diff --git a/plugins/python/python-interfaces.ts b/plugins/python/python-interfaces.ts deleted file mode 100644 index 83b13053..00000000 --- a/plugins/python/python-interfaces.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Python's facts for the interface map: what a declaration line's keyword - * says can execute (interfaces.ts reads them through DECLARES). - */ - -import type { InterfaceSymbol } from "../../src/plugins/api.ts"; - -/** A def or a class has a body; any other top-level declaration is a value. */ -export function pythonDeclares(line: string): InterfaceSymbol["declares"] { - return /^\s*(?:async\s+)?(?:def|class)\s/.test(line) ? "body" : "value"; -} diff --git a/plugins/python/python-scope.ts b/plugins/python/python-scope.ts index 9aa91a6b..4fc1b6b4 100644 --- a/plugins/python/python-scope.ts +++ b/plugins/python/python-scope.ts @@ -1,35 +1,13 @@ /** - * Python's facts for the component interface reading: which declaration - * lines are types or default exports, and what the word index and the kept - * answers read of a file's imports (component-interfaces.ts reads them - * through INTERFACE_SYNTAX, and kept-answers.ts through its wildcardModules). + * Python's facts for the component interface reading that are no reading of + * its text: Pyright narrows its workspace to a reading's bounds. Which + * declarations are types, its default exports (none), and its imports, star + * imports among them, are read through its parser (the manifest's treeSitter); + * an interfaces table states none of them. */ -import { resolveDotted } from "./python.ts"; -import type { InterfaceSyntax } from "../../src/plugins/api.ts"; +import type { InterfaceFacts } from "../../src/plugins/api.ts"; -/** A Python import statement, a parenthesized list or one logical line: `import a as b`, `from m import (a as b, c)`. */ -const PY_IMPORT = /^[ \t]*(?:from\s+\S+\s+)?import\s+(\([^)]*\)|[^\n]*(?:\\\n[^\n]*)*)/gm; -const PY_STAR = /^from\s+(\.*)([A-Za-z0-9_.]*)\s+import\s+\*/gm; - -/** The module files a file star-imports: each dotted module as a .py file and as a package's __init__.py. */ -function starModules(file: string, text: string): string[] { - const modules: string[] = []; - for (const [, dots, dotted] of text.matchAll(PY_STAR)) { - const target = resolveDotted(file, dots!, dotted!); - if (target === undefined) continue; - modules.push(`${target}.py`, `${target}/__init__.py`); - } - return modules; -} - -/** Python declares no type-only names and has no default export; pyright narrows its workspace to the bounds. */ -export const PYTHON_INTERFACES: InterfaceSyntax = { - isTypeDeclaration: () => false, - isDefaultExport: () => false, +export const PYTHON_INTERFACES: InterfaceFacts = { serverBounds: true, - importLists: (text) => [...text.matchAll(PY_IMPORT)].map((m) => m[1]!), - defaultNames: () => [], - wildcardModules: starModules, }; - diff --git a/plugins/python/python-source.ts b/plugins/python/python-source.ts index b53c09b2..252fcb30 100644 --- a/plugins/python/python-source.ts +++ b/plugins/python/python-source.ts @@ -1,25 +1,17 @@ /** - * Python's facts for the plain source scan: which top-level names a line - * declares, which names a file imports, and where a dotted module resolves - * (source.ts reads them through SOURCE_SYNTAX). + * Where a Python import leads: what no parse can say, since a module's place + * is Python's rule, not its syntax. What a file declares and imports is read + * through Python's parser and python.scm (the manifest's treeSitter), so this + * module reads no text. */ import { existsSync } from "node:fs"; import { posix, resolve } from "node:path"; -import type { SourceSyntax } from "../../src/plugins/api.ts"; +import type { ModuleResolution } from "../../src/plugins/api.ts"; +import { resolveDotted } from "./python.ts"; -const PY_DECLARATION = /^(?:async\s+)?(?:def|class)\s+([A-Za-z_]\w*)|^([A-Z_][A-Z0-9_]*)\s*(?::[^=]+)?=/; -const PY_FROM = /^from\s+([\w.]+)\s+import\s+([^\n]+)$/gm; -const PY_IMPORT = /^import\s+([\w.]+)/gm; - -/** A def, a class or a constant is declared; a leading underscore keeps it private; a module is a .py file or a package's __init__.py. */ -export const PYTHON_SOURCE: SourceSyntax = { - declarationOf(line) { - const m = PY_DECLARATION.exec(line); - if (m === null) return undefined; - const name = (m[1] ?? m[2])!; - return { name, exported: !name.startsWith("_") }; - }, +/** A module is a .py file or a package's __init__.py; a leading dot resolves against the importing file's package, each further dot one package up. */ +export const PYTHON_RESOLVE: ModuleResolution = { resolveModule(root, from, specifier, vanished) { const dots = /^(\.*)(.*)$/.exec(specifier)!; const up = dots[1]!.length; @@ -29,13 +21,10 @@ export const PYTHON_SOURCE: SourceSyntax = { const candidates = up === 0 ? [posix.join(...parts) + ".py", posix.join(...parts, "__init__.py")] : [posix.join(base, ...parts) + ".py", posix.join(base, ...parts, "__init__.py")]; return candidates.find((c) => vanished.has(c) || existsSync(resolve(root, c))); }, - importsOf(text, add) { - for (const m of text.matchAll(PY_FROM)) { - for (const piece of m[2]!.replace(/[()]/g, "").split(",")) { - const name = piece.trim().split(/\s+as\s+/)[0]!.trim(); - if (name !== "" && name !== "*") add(name, m[1]!); - } - } - for (const m of text.matchAll(PY_IMPORT)) add(undefined, m[1]!); + // A star import keys the word index by the module as a .py file and as a package's __init__.py, whichever it is. + modulePaths(from, specifier) { + const [, dots, dotted] = /^(\.*)(.*)$/.exec(specifier)!; + const target = resolveDotted(from, dots!, dotted!); + return target === undefined ? [] : [`${target}.py`, `${target}/__init__.py`]; }, }; diff --git a/plugins/python/python-top-level.ts b/plugins/python/python-top-level.ts deleted file mode 100644 index 87662dff..00000000 --- a/plugins/python/python-top-level.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * What the spec model asks of a Python file: whether its top level declares a - * name, by a def or class, or by assigning it (annotated or not). - */ - -/** Whether the text declares the name at its top level. */ -export function pythonDeclaresAtTop(text: string, name: string): boolean { - const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); - return new RegExp(`^(?:async\\s+)?(?:def|class)\\s+${escaped}\\b|^${escaped}\\s*(?::[^=\\n]+)?=`, "m").test(text); -} diff --git a/plugins/python/python.scm b/plugins/python/python.scm new file mode 100644 index 00000000..fbb04d62 --- /dev/null +++ b/plugins/python/python.scm @@ -0,0 +1,33 @@ +; Python's imports and top-level declarations, as the capture names Coherence reads (docs/plugins.md). +; The parser beside it, tree-sitter-python.wasm, is the one the tree-sitter-python 0.25.0 npm package ships, copied as is (language ABI 15). + +; from m import a, b as c, (d, e) -- one match per imported name, whatever lines the statement spans +(import_from_statement + module_name: (_) @import.from + name: (dotted_name) @import.name) @import +(import_from_statement + module_name: (_) @import.from + name: (aliased_import name: (dotted_name) @import.name alias: (identifier) @import.alias)) @import +(import_from_statement + module_name: (_) @import.from + (wildcard_import) @import.glob) @import + +; from __future__ import annotations -- a statement of its own kind, whose module is the keyword +(future_import_statement + "__future__" @import.from + name: (dotted_name) @import.name) @import + +; import a.b, import a.b as c -- the whole module +(import_statement name: (dotted_name) @import.module) @import +(import_statement name: (aliased_import name: (dotted_name) @import.module alias: (identifier) @import.alias)) @import + +; a def or class at the top level, decorated or not, declares a body +(module (function_definition name: (identifier) @name) @declaration.body) +(module (class_definition name: (identifier) @name) @declaration.body) +(module (decorated_definition definition: [(function_definition name: (identifier) @name) (class_definition name: (identifier) @name)]) @declaration.body) + +; a constant assigned there declares a value; any other name assigned there is bound, not declared +; (a module's logger or app is no part of what it offers, and each declaration costs the interface reading a question) +((module (expression_statement (assignment left: (identifier) @name right: (_))) @declaration.value) + (#match? @name "^[A-Z_][A-Z0-9_]*$")) +(module (expression_statement (assignment left: (identifier) @name right: (_))) @bound) diff --git a/plugins/python/python.ts b/plugins/python/python.ts index 7606445d..f51bd182 100644 --- a/plugins/python/python.ts +++ b/plugins/python/python.ts @@ -83,6 +83,7 @@ import { type Definition, type Ladder, type LanguageAdapter, + type ServerSymbol, type Position, type Range, type ReferenceSite, @@ -138,12 +139,15 @@ interface DocumentSymbol { range: Range; selectionRange: Range; children?: DocumentSymbol[]; + /** Set where the server answered a flat SymbolInformation list naming the symbol's container: no top-level symbol. */ + nested?: true; } interface SymbolInformation { name: string; kind: number; location: { uri: string; range: Range }; + containerName?: string; } interface Location { @@ -733,13 +737,18 @@ export class PythonAdapter implements LanguageAdapter { this.opened.delete(file); } + /** The file's top-level symbols as the server reports them: the independent account plugin check and plugin calibrate hold the text readings to. */ + async topLevelSymbols(file: string): Promise { + return (await this.documentSymbols(file)).filter((s) => s.nested !== true).map((s) => ({ name: s.name, line: s.selectionRange.start.line + 1, kind: s.kind })); + } + private async documentSymbols(file: string): Promise { const cached = this.symbolCache.get(file); if (cached !== undefined) return cached; const client = await this.live(); this.open(file); const result = await client.request("textDocument/documentSymbol", { textDocument: { uri: this.uri(file) } }); - const symbols: DocumentSymbol[] = (result ?? []).map((s) => ("location" in s ? { name: s.name, kind: s.kind, range: s.location.range, selectionRange: s.location.range } : s)); + const symbols: DocumentSymbol[] = (result ?? []).map((s) => ("location" in s ? { name: s.name, kind: s.kind, range: s.location.range, selectionRange: s.location.range, ...(s.containerName ? { nested: true as const } : {}) } : s)); this.symbolCache.set(file, symbols); return symbols; } diff --git a/plugins/python/tree-sitter-python.wasm b/plugins/python/tree-sitter-python.wasm new file mode 100644 index 00000000..dc9de36f Binary files /dev/null and b/plugins/python/tree-sitter-python.wasm differ diff --git a/plugins/quint/plugin.json b/plugins/quint/plugin.json index 193d5246..f5b7fd81 100644 --- a/plugins/quint/plugin.json +++ b/plugins/quint/plugin.json @@ -1,7 +1,7 @@ { "name": "quint", "version": "0.1.0", - "pluginApi": 2, + "pluginApi": 4, "module": "index.ts", "verifiers": [ { diff --git a/plugins/rust/check.json b/plugins/rust/check.json index b9f7b658..c5498590 100644 --- a/plugins/rust/check.json +++ b/plugins/rust/check.json @@ -2,15 +2,19 @@ "files": { "Cargo.toml": "[package]\nname = \"shop\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[lib]\npath = \"src/lib.rs\"\n", "src/lib.rs": "pub mod store;\npub mod api;\n", - "src/store/mod.rs": "pub const SECRET_COLUMNS: &[&str] = &[\"token\"];\n\npub fn seal(row: &mut Vec) {\n row.retain(|c| !SECRET_COLUMNS.contains(&c.as_str()));\n}\n", - "src/api/mod.rs": "use crate::store::{seal, SECRET_COLUMNS};\n\npub fn render(row: &mut Vec) -> usize {\n seal(row);\n SECRET_COLUMNS.len()\n}\n", + "src/store/mod.rs": "pub const SECRET_COLUMNS: &[&str] = &[\"token\"];\n\npub fn seal(row: &mut Vec) {\n row.retain(|c| !SECRET_COLUMNS.contains(&c.as_str()));\n}\n\npub mod rows;\n", + "src/api/mod.rs": "use crate::store::{seal, SECRET_COLUMNS};\nuse crate::store::rows::Row;\n\npub fn render(row: &mut Row) -> usize {\n seal(&mut row.0);\n SECRET_COLUMNS.len()\n}\n", "README.md": "# A crate\n", - "src/main.rs": "fn main() {\n let mut row = vec![\"token\".to_string()];\n println!(\"{}\", shop::api::render(&mut row));\n}\n" + "src/main.rs": "use shop::api::render;\nuse shop::store::{\n rows::Row as Stored,\n *,\n};\n\nfn main() {\n use shop::store::rows::Row;\n let mut row: Stored = Row(vec![\"token\".to_string()]);\n println!(\"{}\", render(&mut row));\n}\n", + "src/store/rows.rs": "/// One stored row, by column.\npub struct Row(pub Vec);\n" }, "language": { "files": [ + "src/api/mod.rs", "src/lib.rs", - "src/store/mod.rs" + "src/main.rs", + "src/store/mod.rs", + "src/store/rows.rs" ], "not": [ "README.md", @@ -43,13 +47,13 @@ "chokepoint": "seal", "references": [ "src/api/mod.rs:1", - "src/api/mod.rs:5", + "src/api/mod.rs:6", "src/store/mod.rs:4" ], "grade": "broken", "bypasses": [ "src/api/mod.rs:1", - "src/api/mod.rs:5" + "src/api/mod.rs:6" ], "readings": { "declared": { @@ -65,7 +69,11 @@ ], "src/store/mod.rs": [ "SECRET_COLUMNS", + "rows", "seal" + ], + "src/store/rows.rs": [ + "Row" ] }, "imports": [ @@ -90,6 +98,41 @@ "names": [ "*" ] + }, + { + "file": "src/api/mod.rs", + "module": "src/store/rows.rs", + "names": [ + "Row" + ] + }, + { + "file": "src/store/mod.rs", + "module": "src/store/rows.rs", + "names": [ + "*" + ] + }, + { + "file": "src/main.rs", + "module": "src/api/mod.rs", + "names": [ + "render" + ] + }, + { + "file": "src/main.rs", + "module": "src/store/rows.rs", + "names": [ + "Row" + ] + }, + { + "file": "src/main.rs", + "module": "src/store/mod.rs", + "names": [ + "*" + ] } ], "interfaces": [ @@ -97,7 +140,9 @@ "from": "src/api", "to": "src/store", "symbols": [ + "Row", "SECRET_COLUMNS", + "rows", "seal" ] } @@ -109,5 +154,19 @@ "rule": "binary" } ] + }, + "reference": { + "files": { + "secrets": "src/store/mod.rs", + "rows": "src/store/rows.rs", + "render": "src/api/mod.rs", + "main": "src/main.rs" + }, + "names": { + "SECRET_COLUMNS": "SECRET_COLUMNS", + "seal": "seal", + "Row": "Row", + "render": "render" + } } } diff --git a/plugins/rust/plugin.json b/plugins/rust/plugin.json index f4be9eff..0de7de0d 100644 --- a/plugins/rust/plugin.json +++ b/plugins/rust/plugin.json @@ -1,7 +1,7 @@ { "name": "rust", - "version": "1.10.1", - "pluginApi": 2, + "version": "1.11.0", + "pluginApi": 4, "provides": { "language": "rust" }, @@ -11,6 +11,9 @@ "serverExtensions": [ ".rs" ], + "testFiles": [ + "^tests\\.rs$" + ], "basisFiles": [ "^Cargo\\.toml$", "^Cargo\\.lock$", @@ -51,16 +54,26 @@ { "rule": "foreign export", "plural": "foreign exports", - "detects": "a function carrying #[no_mangle], #[unsafe(no_mangle)], #[export_name = …] or #[wasm_bindgen], which code outside Rust calls by name" + "detects": "a function code outside Rust calls by name: a fn carrying #[no_mangle], #[unsafe(no_mangle)], #[export_name = …], #[wasm_bindgen] (#[wasm_bindgen(start)] included) or #[uniffi::export]; each pub method or constructor of a #[wasm_bindgen] impl, named Type::method; and each pub method of a #[uniffi::export] impl (every method of a trait impl), named Type::method; never a fn of an extern block, which the host provides" + }, + { + "rule": "example", + "plural": "examples", + "detects": "the main of an example at Cargo's default paths, examples/x.rs or examples/x/main.rs, which cargo run --example x runs" } ], - "notDetected": "a router built in a helper and merged in, a route macro of another framework (warp filters, poem), a trait a framework calls (a tonic gRPC service, a tower Service), a message consumer and a proc-macro are not detected" + "notDetected": "a router built in a helper and merged in, a route macro of another framework (warp filters, poem), a trait a framework calls (a tonic gRPC service, a tower Service), a message consumer, a proc-macro, an export a macro generates, a function a UniFFI .udl file declares, the getters and setters wasm-bindgen generates for an exported struct's pub fields, and an example Cargo.toml places away from Cargo's default paths are not detected" }, "markedFolders": [ { "name": "target", "beside": "Cargo.toml", "reason": "Cargo build folder" + }, + { + "name": "pkg", + "beside": "Cargo.toml", + "reason": "wasm-pack output" } ], "ladder": { @@ -80,11 +93,15 @@ ] }, "module": "index.ts", + "treeSitter": { + "parser": "tree-sitter-rust.wasm", + "queries": "rust.scm", + "resolve": "rust-source.ts#RUST_RESOLVE", + "separator": "::" + }, "syntax": { "entrances": "rust-entrances.ts#RUST_ENTRANCES", "interfaces": "rust-scope.ts#RUST_INTERFACES", - "source": "rust-source.ts#RUST_SOURCE", - "declares": "rust-interfaces.ts#rustDeclares", - "topLevel": "rust-top-level.ts#rustDeclaresAtTop" + "lists": "rust-lists.ts#rustListOf" } } diff --git a/plugins/rust/rust-entrances.ts b/plugins/rust/rust-entrances.ts index 0d3a07d4..ae31933c 100644 --- a/plugins/rust/rust-entrances.ts +++ b/plugins/rust/rust-entrances.ts @@ -1,17 +1,25 @@ /** - * Rust's entrance rules and the syntax they read by: a binary's main, a build - * script, the route attributes actix-web and Rocket fix, a route registered - * on an axum or actix-web router, a function exported across a foreign - * boundary (C or wasm), and the binaries Cargo.toml names at a path of their - * own (entrance-candidates.ts reads them through ENTRANCE_SYNTAX). + * Rust's entrance rules and the syntax they read by: a binary's main, an + * example's main, a build script, the route attributes actix-web and Rocket + * fix, a route registered on an axum or actix-web router, a function exported + * across a foreign boundary (C, wasm-bindgen or UniFFI, a free fn or an + * exported impl's method), and the binaries Cargo.toml names at a path of + * their own (entrance-candidates.ts reads them through ENTRANCE_SYNTAX). */ import { posix } from "node:path"; import { handlerName, languageOfFile, spanOf, throughOf, type EntranceCandidate, type EntranceSyntax } from "../../src/plugins/api.ts"; -import { binaryOf, declaredModules, itemOf, manifestOf, testRanges, uncommented, useLeaves } from "./rust-source.ts"; +import { binaryOf, codeOnly, declaredModules, exampleOf, itemOf, manifestOf, testRanges, uncommented, useLeaves } from "./rust-source.ts"; const ROUTE_ATTRIBUTE = /^\s*#\[\s*(?:[\w:]*::)?(get|post|put|patch|delete|head|options|route)\s*\(\s*"([^"]*)"/; -const FOREIGN = /^\s*#\[\s*(no_mangle|unsafe\s*\(\s*no_mangle\s*\)|export_name\s*=|(?:[\w:]*::)?wasm_bindgen\b)/; +// The attributes that export a fn by its name: C's unmangled symbol, wasm-bindgen's binding (plain, by path or under cfg_attr, its arguments captured) and UniFFI's. +const UNMANGLED = /#\[\s*(no_mangle|unsafe\s*\(\s*no_mangle\s*\)|export_name\s*=)/; +const WASM_BINDGEN = /#\[\s*(?:cfg_attr\s*\([^\]]*?,\s*)?(?:[\w:]*::)?wasm_bindgen\b\s*(?:\(([^\]]*)\))?/; +const UNIFFI_EXPORT = /#\[\s*(?:cfg_attr\s*\([^\]]*?,\s*)?(?:::)?uniffi::export\b/; +/** An impl header, its generics passed: what follows is the type, or the trait for the type. */ +const IMPL = /^\s*(?:unsafe\s+)?impl\b(?:\s*<[^{]*?>)?\s+([^{]*)/; +/** An extern block, whose fns the host provides: imports, never exports. */ +const EXTERN_BLOCK = /^\s*(?:pub(?:\s*\([^)]*\))?\s+)?(?:unsafe\s+)?extern(?:\s+"[^"]*")?\s*\{/; /** A handler argument: a path, or a call wrapping one, one level deep. */ const ARGUMENT = String.raw`([\w:]+(?:\s*\([^()]*\))?)`; const METHOD = new RegExp(String.raw`(?:\b(?:get|post|put|patch|delete|head|options|trace|any)|\.to)\s*\(\s*${ARGUMENT}\s*\)`, "g"); @@ -28,6 +36,140 @@ function isMain(line: string): boolean { return item?.top === true && item.keyword === "fn" && item.name === "main"; } +/** The type an impl header is for: impl Viewer and impl Shape for Ring are Viewer and Ring. */ +function implType(header: string): string | undefined { + const target = /\bfor\s+(.+)$/.exec(header)?.[1] ?? header; + return /^&?\s*(?:'\w+\s+)?(?:mut\s+)?(?:(?:r#)?[A-Za-z_]\w*::)*(?:r#)?([A-Za-z_]\w*)/.exec(target.trim())?.[1]; +} + +/** Whether a wasm_bindgen attribute's arguments name the flag (constructor, getter, skip), as one of its comma-separated arguments and never a value. */ +function flag(args: string, name: string): boolean { + return new RegExp(`(?:^|,)\\s*${name}\\s*(?=[,=]|$)`).test(args.trim()); +} + +/** A fn code outside Rust calls by name: where its attributes start, its symbol, and why. */ +interface ForeignExport { + start: number; + symbol: string; + why: string; +} + +/** A block the scan is inside: an impl (its type, and what exports it), an extern block, or any other. */ +interface Block { + kind: "impl" | "extern" | "other"; + type?: string; + exports?: "wasm" | "uniffi"; + trait?: boolean; +} + +/** + * The fns a file exports across a foreign boundary, read line by line with + * its blocks tracked by their braces (over the code alone, so a brace in a + * string is none): a free fn under an exporting attribute; a pub method of a + * #[wasm_bindgen] impl, a trait's impl excepted (wasm-bindgen exports + * inherent impls alone) and a #[wasm_bindgen(skip)] one too; a method of a + * #[uniffi::export] impl, pub, or any of a trait impl's; never a fn of an + * extern block, which the host provides. + */ +function foreignExports(lines: readonly string[], code: readonly string[]): ForeignExport[] { + const out: ForeignExport[] = []; + const stack: Block[] = []; + let attributes = ""; + let attributesAt = -1; + let open = 0; + /** The block the next brace opens, when a header above it says what it is. */ + let next: Block | undefined; + for (let i = 0; i < code.length; i++) { + const line = code[i]!; + // The attributes at the line's start, each whole across lines (#[wasm_bindgen(\n js_name = x\n)]), read from the text as written. + let at = 0; + for (;;) { + if (open === 0) { + const lead = /^\s*/.exec(line.slice(at))![0].length; + if (!line.startsWith("#[", at + lead)) break; + if (attributesAt < 0) attributesAt = i; + at += lead; + } + let j = at; + for (; j < line.length; j++) { + if (line[j] === "[") open += 1; + else if (line[j] === "]" && --open === 0) { + j += 1; + break; + } + } + attributes += ` ${(lines[i] ?? "").slice(at, j).trim()}`; + at = j; + if (open > 0) break; + } + const rest = line.slice(at); + if (open > 0 || rest.trim() === "") continue; + const inner = stack[stack.length - 1]; + const fn = itemOf(rest); + const impl = IMPL.exec(rest); + if (EXTERN_BLOCK.test(rest)) next = { kind: "extern" }; + else if (impl !== null) { + const header = impl[1]!; + const type = implType(header); + const trait = /\bfor\s/.test(header); + // An impl whose type cannot be read names no method, so it exports none the scan can name. + const exports = type === undefined ? undefined : WASM_BINDGEN.test(attributes) && !trait ? "wasm" : UNIFFI_EXPORT.test(attributes) ? "uniffi" : undefined; + next = { kind: "impl", ...(type === undefined ? {} : { type }), ...(exports === undefined ? {} : { exports }), trait }; + } else if (fn?.keyword === "fn") { + next = { kind: "other" }; + const start = attributesAt < 0 ? i : attributesAt; + // pub alone: pub(crate) and pub(super) are not seen outside the crate. + const pub = /^\s*pub\s/.test(rest); + if (stack.some((b) => b.kind === "extern")) { + // An import, which the host provides. + } else if (inner?.kind === "impl") { + const symbol = `${inner.type}::${fn.name}`; + const wasm = WASM_BINDGEN.exec(attributes); + const args = wasm?.[1] ?? ""; + if (inner.exports === "wasm" && pub && !flag(args, "skip")) { + const why = flag(args, "constructor") + ? `${symbol} is the #[wasm_bindgen(constructor)] of a #[wasm_bindgen] impl: JavaScript's new ${inner.type}(…) calls it` + : flag(args, "getter") || flag(args, "setter") + ? `${symbol} is a #[wasm_bindgen(${flag(args, "getter") ? "getter" : "setter"})] of a #[wasm_bindgen] impl: JavaScript reaches it as a ${inner.type}'s property` + : `${symbol} is a pub method of a #[wasm_bindgen] impl: JavaScript calls it on a ${inner.type}`; + out.push({ start, symbol, why }); + } + // A trait impl's methods carry no visibility of their own: UniFFI exports every one. + if (inner.exports === "uniffi" && (pub || inner.trait === true)) { + const why = /#\[\s*(?:::)?uniffi::constructor\b/.test(attributes) + ? `${symbol} is a #[uniffi::constructor] of a #[uniffi::export] impl: Swift, Kotlin or Python constructs a ${inner.type} through it` + : `${symbol} is a method of a #[uniffi::export] impl: Swift, Kotlin or Python calls it on a ${inner.type}`; + out.push({ start, symbol, why }); + } + } else { + const wasm = WASM_BINDGEN.exec(attributes); + const unmangled = UNMANGLED.exec(attributes); + if (wasm !== null && !flag(wasm[1] ?? "", "skip")) { + const why = flag(wasm[1] ?? "", "start") + ? `${fn.name} carries #[wasm_bindgen(start)]: it runs when JavaScript instantiates the module` + : `${fn.name} carries #[wasm_bindgen]: code outside Rust calls it by that name`; + out.push({ start, symbol: fn.name, why }); + } else if (UNIFFI_EXPORT.test(attributes)) { + out.push({ start, symbol: fn.name, why: `${fn.name} carries #[uniffi::export]: Swift, Kotlin or Python calls it through the bindings UniFFI generates` }); + } else if (unmangled !== null) { + out.push({ start, symbol: fn.name, why: `${fn.name} carries #[${unmangled[1]!.replace(/\s*=$/, "").replace(/\s+/g, "")}]: code outside Rust calls it by that name` }); + } + } + } else if (fn !== undefined) next = undefined; + for (const c of rest) { + if (c === "{") { + stack.push(next ?? { kind: "other" }); + next = undefined; + } else if (c === "}") stack.pop(); + } + // A header that ends in ; opens no block: a trait's or an extern block's fn without a body. + if (/;\s*$/.test(rest)) next = undefined; + attributes = ""; + attributesAt = -1; + } + return out; +} + /** The last segment of a path expression: handlers::create is create. */ function lastSegment(path: string): string { return path.split("::").pop() ?? path; @@ -61,20 +203,22 @@ function rustCandidates(file: string, original: string, wrappers: readonly strin const seen = new Set(); const script = /(^|\/)build\.rs$/.test(file); const binary = binaryOf(file); + const example = exampleOf(file); lines.forEach((line, i) => { const main = isMain(line); if (main && binary !== undefined) add({ file, line: i + 1, symbol: "main", rule: "binary", name: `binary ${binary}`, why: `${file} is a binary's root by Cargo's layout, and main runs when the binary starts` }, spanOf(lines, i, RUST_ENTRANCES)); + if (main && example !== undefined) add({ file, line: i + 1, symbol: "main", rule: "example", name: `example ${example}`, why: `${file} is an example's root by Cargo's layout, and main runs when cargo run --example ${example} starts it` }, spanOf(lines, i, RUST_ENTRANCES)); if (main && script) add({ file, line: i + 1, symbol: "main", rule: "build script", name: `build script ${posix.basename(posix.dirname(file)).replace(/^\.$/, "crate")}`, why: "Cargo runs build.rs's main before it compiles the crate" }, spanOf(lines, i, RUST_ENTRANCES)); const route = ROUTE_ATTRIBUTE.exec(line); - const foreign = FOREIGN.exec(line); - if (route === null && foreign === null) return; + if (route === null) return; const target = attributed(i); if (target === undefined || seen.has(target.start)) return; seen.add(target.start); - const span = spanOf(lines, target.start, RUST_ENTRANCES); - if (route !== null) add({ file, line: target.start + 1, symbol: target.name, rule: "route attribute", why: `${target.name} carries #[${route[1]}("${route[2]}")]: a web route` }, span); - else add({ file, line: target.start + 1, symbol: target.name, rule: "foreign export", why: `${target.name} carries #[${foreign![1]!.replace(/\s*=$/, "").replace(/\s+/g, "")}]: code outside Rust calls it by that name` }, span); + add({ file, line: target.start + 1, symbol: target.name, rule: "route attribute", why: `${target.name} carries #[${route[1]}("${route[2]}")]: a web route` }, spanOf(lines, target.start, RUST_ENTRANCES)); }); + for (const { start, symbol, why } of foreignExports(lines, codeOnly(original).split("\n"))) { + add({ file, line: start + 1, symbol, rule: "foreign export", why }, spanOf(lines, start, RUST_ENTRANCES)); + } // A router's route is read over the whole text: a chain breaks across lines, its path and its handlers on the lines below. const lineAt = (index: number): number => text.slice(0, index).split("\n").length; for (const call of text.matchAll(/\.route\(\s*"([^"]*)"\s*,/g)) { diff --git a/plugins/rust/rust-interfaces.ts b/plugins/rust/rust-interfaces.ts deleted file mode 100644 index 1187d2ab..00000000 --- a/plugins/rust/rust-interfaces.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Rust's facts for the interface map: what a declaration line's keyword - * says can execute (interfaces.ts reads them through DECLARES). - */ - -import type { InterfaceSymbol } from "../../src/plugins/api.ts"; -import { itemOf } from "./rust-source.ts"; - -/** - * A fn or a macro has a body, and so does a struct, enum or union, whose - * impl blocks are its methods (as a TypeScript class's are); a trait or a - * type alias declares a type; a const or static is a value; a module is - * counted as able to execute, so never read as bodiless. - */ -export function rustDeclares(line: string): InterfaceSymbol["declares"] { - const item = itemOf(line); - const keyword = item?.top === true ? item.keyword : undefined; - if (keyword === undefined || keyword === "mod") return "unknown"; - if (keyword === "macro_rules") return "body"; - if (keyword === "trait" || keyword === "type") return "type"; - if (keyword === "const" || keyword === "static") return "value"; - return "body"; -} diff --git a/plugins/rust/rust-lists.ts b/plugins/rust/rust-lists.ts new file mode 100644 index 00000000..42a5e8dd --- /dev/null +++ b/plugins/rust/rust-lists.ts @@ -0,0 +1,107 @@ +/** + * Rust's mirror reader (the lists slot): the literal a top-level const or + * static is set to, read as the declared mirrors read a TypeScript list + * (mirrors.ts reads it through SyntaxTables.lists). A list a Rust file keeps + * by hand beside one elsewhere (a shader's bindings, a client's names, a + * schema's kinds) is one of these: + * + * pub const KINDS: &[&str] = &["box", "sphere", "plane"]; + * static TABLE: [(&str, u32); 2] = [("a", 1), ("b", 2)]; + * + * An array (behind any &, or in vec![…]) counts its string literals, a tuple + * by its first element, as a TypeScript table's rows count by their first + * column; a path (Kind::Box) counts by its last segment, the name it spells. + * What it cannot read as a member (a number, a call, a nested array) is kept + * as written, so a mirror over it compares nothing rather than something + * wrong. Comments are skipped; a raw string reads as its contents. + */ + +import type { Literal } from "../../src/plugins/api.ts"; +import { codeOnly, itemOf, uncommented } from "./rust-source.ts"; + +/** + * The top-level segments between the bracket opening at `open` and its + * match, cut from `text` where `code` (the same text with its literals and + * comments blanked, every offset kept) shows the brackets and commas; + * undefined when it never closes. + */ +function segmentsOf(code: string, text: string, open: number): string[] | undefined { + const segments: string[] = []; + let depth = 0; + let from = open + 1; + for (let i = open; i < code.length; i++) { + const c = code[i]; + if (c === "[" || c === "{" || c === "(") depth += 1; + else if (c === "]" || c === "}" || c === ")") { + depth -= 1; + if (depth === 0) { + const last = text.slice(from, i).trim(); + if (last !== "") segments.push(last); + return segments; + } + } else if (c === "," && depth === 1) { + segments.push(text.slice(from, i).trim()); + from = i + 1; + } + } + return undefined; +} + +/** A segment that is one string literal, plain, byte or raw: its value. */ +function stringValue(segment: string): string | undefined { + const raw = /^b?r(#*)"([\s\S]*)"\1$/.exec(segment); + if (raw !== null) return raw[2]; + const plain = /^b?"((?:\\[\s\S]|[^"\\])*)"$/.exec(segment); + return plain === null ? undefined : plain[1]!.replace(/\\(.)/g, "$1"); +} + +function member(segment: string): string | undefined { + const value = stringValue(segment); + if (value !== undefined) return value; + // A tuple counts by its first element: a table's rows by their first column. + if (segment.startsWith("(")) { + const inner = segmentsOf(codeOnly(segment), segment, 0); + return inner === undefined || inner.length === 0 ? undefined : member(inner[0]!); + } + // A path spells its last segment: Kind::Box is Box. + return /^(?:(?:r#)?[A-Za-z_]\w*::)+(?:r#)?([A-Za-z_]\w*)$/.exec(segment.replace(/\s+/g, ""))?.[1]; +} + +/** The literal a top-level const or static named `name` is set to, or undefined when none is set to an array. */ +export function rustListOf(original: string, name: string): Literal | undefined { + const text = uncommented(original); + const code = codeOnly(original); + const lines = code.split("\n"); + const at = lines.findIndex((line) => { + const item = itemOf(line); + return item?.top === true && (item.keyword === "const" || item.keyword === "static") && item.name === name; + }); + if (at < 0) return undefined; + const start = lines.slice(0, at).reduce((n, line) => n + line.length + 1, 0); + // The = that sets it: past the type annotation, whose brackets ([&str; 3]) may hold a ; but no =. + let i = start + lines[at]!.indexOf(name) + name.length; + let depth = 0; + for (; i < code.length; i++) { + const c = code[i]; + if (c === "[" || c === "(" || c === "<") depth += 1; + else if (c === "]" || c === ")" || (c === ">" && code[i - 1] !== "-")) depth -= 1; + else if (c === ";" && depth === 0) return undefined; + else if (c === "=" && depth === 0 && code[i + 1] !== "=" && code[i + 1] !== ">") break; + } + if (i >= code.length) return undefined; + // Past any & and a vec! that hold the array. + const rest = /^\s*(?:&\s*(?:'static\s+)?(?:mut\s+)?)*(?:vec!\s*)?/.exec(code.slice(i + 1))![0]; + const open = i + 1 + rest.length; + if (code[open] !== "[") return undefined; + const segments = segmentsOf(code, text, open); + if (segments === undefined) return undefined; + const members: string[] = []; + const unread: string[] = []; + for (const segment of segments) { + if (segment === "") continue; + const value = member(segment); + if (value === undefined) unread.push(segment.length > 40 ? `${segment.slice(0, 37)}...` : segment); + else members.push(value); + } + return { line: at + 1, kind: "array", members, unread }; +} diff --git a/plugins/rust/rust-scope.ts b/plugins/rust/rust-scope.ts index 88d12f6f..170b543c 100644 --- a/plugins/rust/rust-scope.ts +++ b/plugins/rust/rust-scope.ts @@ -1,42 +1,14 @@ /** - * Rust's facts for the component interface reading: which declaration lines - * are types, what the word index reads of a file's use trees, and the - * modules a file glob-imports (component-interfaces.ts reads them through - * INTERFACE_SYNTAX, kept-answers.ts through the same wildcardModules). + * Rust's facts for the component interface reading that are no reading of + * its text: rust-analyzer reads its Cargo workspace, so it takes no bounds. + * Which declaration is a type, its default exports (Rust has none, and its + * queries capture none), and which names a file imports renamed or by a glob + * are read through Rust's parser and rust.scm; an interfaces table states + * none of them. */ -import { posix } from "node:path"; -import type { InterfaceSyntax } from "../../src/plugins/api.ts"; -import { absolutePath, crateRootOf, itemOf, useLeaves, useTrees } from "./rust-source.ts"; +import type { InterfaceFacts } from "../../src/plugins/api.ts"; -/** The module files a file glob-imports (`use crate::a::*`), in both layouts the word index may key a module by: a.rs and a/mod.rs. */ -function globModules(file: string, text: string): string[] { - const crateRoot = crateRootOf(file); - if (crateRoot === undefined) return []; - const modules: string[] = []; - for (const leaf of useLeaves(text)) { - if (leaf.path[leaf.path.length - 1] !== "*") continue; - const absolute = absolutePath(file, crateRoot, leaf.path.slice(0, -1)); - if (absolute === undefined) continue; - if (absolute.length === 0) { - modules.push(crateRoot); - continue; - } - const base = posix.join(posix.dirname(crateRoot), ...absolute); - modules.push(`${base}.rs`, `${base}/mod.rs`); - } - return modules; -} - -/** A type alias declares a type only; Rust has no default export; rust-analyzer reads its Cargo workspace, so it takes no bounds. */ -export const RUST_INTERFACES: InterfaceSyntax = { - isTypeDeclaration(line) { - const item = itemOf(line); - return item?.top === true && item.keyword === "type"; - }, - isDefaultExport: () => false, +export const RUST_INTERFACES: InterfaceFacts = { serverBounds: false, - importLists: useTrees, - defaultNames: () => [], - wildcardModules: globModules, }; diff --git a/plugins/rust/rust-source.ts b/plugins/rust/rust-source.ts index ed5b6c64..0cef0836 100644 --- a/plugins/rust/rust-source.ts +++ b/plugins/rust/rust-source.ts @@ -1,24 +1,24 @@ /** - * Rust's facts for the plain source scan: which items a line declares at the - * top level, which names a file brings in by `use` and `mod`, and where a - * module path resolves (source.ts reads them through SOURCE_SYNTAX). + * Rust's model of its own code where no parse answers: where a module path + * resolves (RUST_RESOLVE, the manifest's treeSitter.resolve), what Cargo's + * layout and manifests make a crate root, a binary or an example, and the + * line readings the entrance and lists slots still read by (an item, a use + * tree, comments, literals and test-only items set apart). What a file + * declares at its top level and what it imports is read through Rust's + * parser and rust.scm, never here. * * A path resolves by Cargo's layout, not by rust-analyzer: a file's crate * root is found from its path (crateRootOf) or the manifests' target paths * (workspaceOf), and a module's file is /.rs or - * //mod.rs. A #[path] attribute and a module declared inline - * (`mod a { … }`) are not followed; a path into a crate outside the - * workspace resolves to nothing. - * - * This file is the plugin's one model of Rust: what an item is, what the - * layout and the manifests make a crate root or a binary, and what code is - * (comments, literals and test-only items set apart). The other files read - * Rust through it. + * //mod.rs. A #[path] attribute is not followed; a path into a + * crate outside the workspace resolves to nothing; and a path written inside + * an inline module (mod tests { … }) is read from that module, so it leads + * to no other file unless it leaves the file's own module. */ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs"; import { posix, resolve } from "node:path"; -import { parseToml, type SourceSyntax, type TomlTable, type TomlValue } from "../../src/plugins/api.ts"; +import { parseToml, type ModuleResolution, type TomlTable, type TomlValue } from "../../src/plugins/api.ts"; /** An item: its indentation, under any visibility and qualifier, its keyword, then its name; or a macro_rules! macro. */ const ITEM = /^(\s*)(?:(pub(?:\s*\([^)]*\))?\s+)?(?:(?:default|const|async|unsafe|extern(?:\s+"[^"]*")?)\s+)*(fn|struct|enum|union|trait|type|const|static(?:\s+mut)?|mod)\s+|(macro_rules!)\s*)(?:r#)?([A-Za-z_][A-Za-z0-9_]*)/; @@ -130,11 +130,6 @@ export function useLeaves(text: string): UseLeaf[] { return out; } -/** The text of each use declaration's tree, where its `original as alias` renames are read from. */ -export function useTrees(text: string): string[] { - return [...codeOnly(text).matchAll(/(?:^|[;{}\s])(?:pub(?:\s*\([^)]*\))?\s+)?use\s+([^;]+);/g)].map((m) => m[1]!); -} - /** The modules a file declares out of line: `mod a;`, never an inline `mod a { … }`. */ export function declaredModules(text: string): string[] { return [...codeOnly(text).matchAll(/^\s*(?:pub(?:\s*\([^)]*\))?\s+)?mod\s+(?:r#)?([A-Za-z_]\w*)\s*;/gm)].map((m) => m[1]!); @@ -176,6 +171,18 @@ export function binaryOf(file: string): string | undefined { return parts[src - 1] ?? "crate"; } +/** + * The example a file is the root of by Cargo's default paths, by the name + * cargo run --example takes: examples/demo.rs and examples/demo/main.rs are + * demo. Undefined for any other file, and for an examples folder inside a + * src/ folder, which is a module's and no package's. + */ +export function exampleOf(file: string): string | undefined { + const m = /(?:^|\/)examples\/([^/]+?)(?:\.rs|\/main\.rs)$/.exec(file); + if (m === null) return undefined; + return file.slice(0, m.index).split("/").includes("src") ? undefined : m[1]; +} + /** The module path a file defines within its crate: [] for the crate root, [a, b] for a/b.rs or a/b/mod.rs. */ export function modulePathOf(file: string, crateRoot: string): string[] { if (file === crateRoot) return []; @@ -342,34 +349,78 @@ function spelled(root: string, file: string): boolean { } } -/** A pub item is seen outside its file (pub(crate) and pub(super) included); a private one only in its module. */ -export const RUST_SOURCE: SourceSyntax = { - declarationOf(line) { - const item = itemOf(line); - return item === undefined || !item.top ? undefined : { name: item.name, exported: item.exported }; - }, +/** + * A specifier as the parse spells it (rust.scm), read as a path: its + * segments, white space and raw identifiers' r# dropped; a group's trailing + * self (use a::{self}) read as the group's module; and its leading mod + * segments, one per inline module the use sits in (mod is a keyword, so no + * path spells it), counted apart. Undefined for a path that names nothing on + * its own (use {self}). + */ +function pathOf(specifier: string): { inline: number; path: string[] } | undefined { + const all = specifier.replace(/\s+/g, "").split("::").map((p) => p.replace(/^r#/, "")); + let inline = 0; + while (all[inline] === "mod") inline += 1; + const path = all.slice(inline); + if (path[path.length - 1] === "self" && path.length > 1) path.pop(); + if (path.length === 0 || (path.length === 1 && path[0] === "self")) return undefined; + return { inline, path }; +} + +/** + * A path written inside inline modules, as a path from the file's own module: + * crate:: and the extern prelude's :: read the same anywhere; each super + * leaves one inline module before it leaves the file's; a path still inside + * an inline module (self::, or super:: short of the file) names an item of + * this file, never another (undefined); and a bare path there names a crate + * (Rust 2018 reads a bare use path as a crate or an item of the module it is + * in), so it is read as a crate alone. + */ +function fromFile(inline: number, path: readonly string[]): { path: string[]; crateOnly: boolean } | undefined { + if (inline === 0 || path[0] === "crate" || path[0] === "") return { path: [...path], crateOnly: false }; + let up = 0; + while (path[up] === "super") up += 1; + if (up === 0) return path[0] === "self" ? undefined : { path: [...path], crateOnly: true }; + if (up < inline) return undefined; + return up === inline ? { path: ["self", ...path.slice(up)], crateOnly: false } : { path: [...path.slice(inline)], crateOnly: false }; +} + +/** + * Where a Rust import leads, read by Cargo's layout and the workspace's + * manifests (what no parse can say): a path from the file's crate root + * (crate::, self::, super::, or a module of the file's own), else a crate of + * the workspace by its package name. What a file declares and imports is + * read through Rust's parser and rust.scm (the manifest's treeSitter), each + * use path both as an item of a module and as the module itself; only the + * reading that resolves is kept. + */ +export const RUST_RESOLVE: ModuleResolution = { resolveModule(root, from, specifier, vanished) { + const read = pathOf(specifier); + const within = read === undefined ? undefined : fromFile(read.inline, read.path); + if (within === undefined) return undefined; + const { path } = within; const exists = (file: string): boolean => vanished.has(file) || spelled(root, file); - const path = specifier.split("::"); const workspace = workspaceOf(root); - const own = resolvePath(exists, from, path, crateRootIn(workspace, from)); - if (own !== undefined) return own; + if (!within.crateOnly) { + const own = resolvePath(exists, from, path, crateRootIn(workspace, from)); + if (own !== undefined) return own; + } // A path into another crate of the workspace: its first segment names the crate, the rest a module from its root. const crateRoot = workspace.crates.get(path[0] === "" ? path[1] ?? "" : path[0]!); return crateRoot === undefined ? undefined : moduleFileOf(exists, crateRoot, path.slice(path[0] === "" ? 2 : 1)); }, - importsOf(text, add) { - for (const leaf of useLeaves(text)) { - const last = leaf.path[leaf.path.length - 1]!; - const prefix = leaf.path.slice(0, -1); - if (last === "*" || last === "self") { - if (prefix.length > 0) add(undefined, prefix.join("::")); - continue; - } - // `use a::b` names an item of a or the module a::b; each is handed on, and only the one that resolves is kept. - if (prefix.length > 0) add(last, prefix.join("::")); - add(undefined, leaf.path.join("::")); - } - for (const name of declaredModules(text)) add(undefined, `self::${name}`); + // A glob keys the word index by its module in both layouts a module may take: a.rs and a/mod.rs. + modulePaths(from, specifier) { + const crateRoot = crateRootOf(from); + const read = pathOf(specifier); + const within = read === undefined ? undefined : fromFile(read.inline, read.path); + if (crateRoot === undefined || within === undefined || within.crateOnly) return []; + const absolute = absolutePath(from, crateRoot, within.path); + // A glob of the file's own module (mod tests { use super::*; }) names no other file. + if (absolute === undefined || absolute.join("/") === modulePathOf(from, crateRoot).join("/")) return []; + if (absolute.length === 0) return [crateRoot]; + const base = posix.join(posix.dirname(crateRoot), ...absolute); + return [`${base}.rs`, `${base}/mod.rs`]; }, }; diff --git a/plugins/rust/rust-top-level.ts b/plugins/rust/rust-top-level.ts deleted file mode 100644 index fef5cb15..00000000 --- a/plugins/rust/rust-top-level.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * What the spec model asks of a Rust file: whether its top level declares a - * name, an item at column zero (a fn, struct, enum, union, trait, type alias, - * const, static or mod, under any visibility, async, const, unsafe or extern - * qualifier) or a macro_rules! macro, so a handler written in Rust (a wasm or - * FFI export, a dispatcher) is declared as TypeScript's and Python's are. - */ - -import { RUST_SOURCE } from "./rust-source.ts"; - -/** Whether the text declares the name at its top level. */ -export function rustDeclaresAtTop(text: string, name: string): boolean { - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) return false; - return text.split("\n").some((line) => RUST_SOURCE.declarationOf(line.replace(/\r$/, ""))?.name === name); -} diff --git a/plugins/rust/rust.scm b/plugins/rust/rust.scm new file mode 100644 index 00000000..f6f0bdd2 --- /dev/null +++ b/plugins/rust/rust.scm @@ -0,0 +1,48 @@ +; Rust's imports and top-level declarations, as the capture names Coherence reads (docs/plugins.md). +; The parser beside it, tree-sitter-rust.wasm, is the one the tree-sitter-rust 0.24.0 npm package ships, copied as is (language ABI 14). + +; Every use declaration is a statement, wherever it stands (in a fn, in an inline mod), so the census can say which sit inside a block. +(use_declaration) @import + +; A use path names an item of a module or the module itself, and the text cannot say which, so each is read both ways: +; use a::b is b from a and the module a::b, and where it leads keeps the one that resolves (rust-source.ts RUST_RESOLVE). +(use_declaration argument: (scoped_identifier path: (_) @import.from name: (identifier) @import.name)) +(use_declaration argument: [(scoped_identifier) (identifier)] @import.module) +(use_declaration argument: (use_as_clause path: (scoped_identifier path: (_) @import.from name: (identifier) @import.name) alias: (_) @import.alias)) +(use_declaration argument: (use_as_clause path: (_) @import.module alias: (_) @import.alias)) + +; use a::* brings in every name a exports, and depends on a whole +(use_declaration argument: (use_wildcard (_) @import.from) @import.glob) +(use_declaration argument: (use_wildcard (_) @import.module)) + +; use a::{b, c::{self, d as e}, f::*}: a group's path prefixes every path inside it, to any depth (the core joins them with the separator, ::), +; so each leaf reads as though written alone: b from a, the module a::c (self), d from a::c renamed e, every name of a::f +(scoped_use_list path: (_) @import.prefix) +(scoped_use_list path: (_) @import.from list: (use_list (identifier) @import.name)) +(scoped_use_list path: (_) @import.from list: (use_list (use_as_clause path: (identifier) @import.name alias: (_) @import.alias))) +(scoped_use_list path: (_) @import.from list: (use_list (use_wildcard . "*") @import.glob)) +(scoped_use_list path: (_) @import.module list: (use_list (use_wildcard . "*"))) +(use_list [(identifier) (scoped_identifier) (self)] @import.module) +(use_list (scoped_identifier path: (_) @import.from name: (identifier) @import.name)) +(use_list (use_as_clause path: (scoped_identifier path: (_) @import.from name: (identifier) @import.name) alias: (_) @import.alias)) +(use_list (use_as_clause path: (_) @import.module alias: (_) @import.alias)) +(use_list (use_wildcard (_) @import.from) @import.glob) +(use_list (use_wildcard (_) @import.module)) + +; mod x; brings in the module file x beside this one; an inline mod's keyword prefixes every path inside it, +; so a use there (mod tests { use super::*; }) is read from the inline module, not from the file's +(mod_item name: (identifier) @import.module !body) @import +(mod_item "mod" @import.prefix body: (declaration_list)) + +; an item at the top level, under any visibility (pub in every form exports it): a fn, struct, enum, union or macro_rules! has a body +; (a type's impl blocks are its methods), a trait or a type alias declares a type, a const or static a value, and a module is counted able to execute +(source_file (function_item (visibility_modifier)? @exported name: (identifier) @name) @declaration.body) +(source_file (struct_item (visibility_modifier)? @exported name: (type_identifier) @name) @declaration.body) +(source_file (enum_item (visibility_modifier)? @exported name: (type_identifier) @name) @declaration.body) +(source_file (union_item (visibility_modifier)? @exported name: (type_identifier) @name) @declaration.body) +(source_file (macro_definition name: (identifier) @name) @declaration.body) +(source_file (trait_item (visibility_modifier)? @exported name: (type_identifier) @name) @declaration.type) +(source_file (type_item (visibility_modifier)? @exported name: (type_identifier) @name) @declaration.type) +(source_file (const_item (visibility_modifier)? @exported name: (identifier) @name) @declaration.value) +(source_file (static_item (visibility_modifier)? @exported name: (identifier) @name) @declaration.value) +(source_file (mod_item (visibility_modifier)? @exported name: (identifier) @name) @declaration.unknown) diff --git a/plugins/rust/rust.ts b/plugins/rust/rust.ts index e0b3c8e3..7ccacef0 100644 --- a/plugins/rust/rust.ts +++ b/plugins/rust/rust.ts @@ -39,6 +39,7 @@ import { type Definition, type Ladder, type LanguageAdapter, + type ServerSymbol, type Position, type Range, type ReferenceSite, @@ -98,12 +99,15 @@ interface DocumentSymbol { range: Range; selectionRange: Range; children?: DocumentSymbol[]; + /** Set where the server answered a flat SymbolInformation list naming the symbol's container: no top-level symbol. */ + nested?: true; } interface SymbolInformation { name: string; kind: number; location: { uri: string; range: Range }; + containerName?: string; } interface Location { @@ -508,6 +512,11 @@ export class RustAdapter implements LanguageAdapter { this.symbolCache.delete(file); } + /** The file's top-level symbols as the server reports them: the independent account plugin check and plugin calibrate hold the text readings to. */ + async topLevelSymbols(file: string): Promise { + return (await this.documentSymbols(file)).filter((s) => s.nested !== true).map((s) => ({ name: s.name, line: s.selectionRange.start.line + 1, kind: s.kind })); + } + private async documentSymbols(file: string): Promise { const cached = this.symbolCache.get(file); if (cached !== undefined) return cached; @@ -516,7 +525,7 @@ export class RustAdapter implements LanguageAdapter { return []; } const result = await this.ask("textDocument/documentSymbol", { textDocument: { uri: this.uri(file) } }); - const symbols: DocumentSymbol[] = (result ?? []).map((s) => ("location" in s ? { name: s.name, kind: s.kind, range: s.location.range, selectionRange: s.location.range } : s)); + const symbols: DocumentSymbol[] = (result ?? []).map((s) => ("location" in s ? { name: s.name, kind: s.kind, range: s.location.range, selectionRange: s.location.range, ...(s.containerName ? { nested: true as const } : {}) } : s)); this.symbolCache.set(file, symbols); return symbols; } diff --git a/plugins/rust/tree-sitter-rust.wasm b/plugins/rust/tree-sitter-rust.wasm new file mode 100644 index 00000000..b7e0c4b3 Binary files /dev/null and b/plugins/rust/tree-sitter-rust.wasm differ diff --git a/plugins/typescript/check.json b/plugins/typescript/check.json index 786eb71b..f4114e58 100644 --- a/plugins/typescript/check.json +++ b/plugins/typescript/check.json @@ -2,17 +2,21 @@ "files": { "tsconfig.json": "{ \"compilerOptions\": { \"target\": \"ES2022\", \"module\": \"NodeNext\", \"moduleResolution\": \"NodeNext\", \"strict\": true, \"noEmit\": true, \"allowImportingTsExtensions\": true }, \"include\": [\"src/**/*.ts\"] }\n", "src/store/secrets.ts": "/** The protected thing. */\nexport const SECRET_COLUMNS: Record = { tokens: [\"token\"] };\n\n/** The chokepoint: the one way a row leaves without its secrets. */\nexport function seal(pattern: string, row: Record): Record {\n const out = { ...row };\n for (const column of SECRET_COLUMNS[pattern] ?? []) delete out[column];\n return out;\n}\n", - "src/api/render.ts": "import { SECRET_COLUMNS, seal } from \"../store/secrets.ts\";\n\nexport function render(pattern: string, row: Record): string {\n const sealed = seal(pattern, row);\n const leaked = SECRET_COLUMNS[pattern];\n return JSON.stringify({ sealed, leaked });\n}\n", + "src/api/render.ts": "import { SECRET_COLUMNS, seal } from \"../store/secrets.ts\";\nimport type { Row } from \"../store/rows.ts\";\n\nexport function render(pattern: string, row: Row): string {\n const sealed = seal(pattern, row);\n const leaked = SECRET_COLUMNS[pattern];\n return JSON.stringify({ sealed, leaked });\n}\n", "src/__tests__/secrets.test.ts": "import { SECRET_COLUMNS } from \"../store/secrets.ts\";\nexport const t = SECRET_COLUMNS;\n", "README.md": "# A project\n", - "src/api/routes.ts": "import { render } from \"./render.ts\";\n\nexport const app = {\n get(path: string, handler: (row: Record) => string): readonly [string, (row: Record) => string] {\n return [path, handler] as const;\n },\n};\n\nexport function rows(row: Record): string {\n return render(\"tokens\", row);\n}\n\napp.get(\"/rows\", rows);\n" + "src/api/routes.ts": "import { render } from \"./render.ts\";\n\nexport const app = {\n get(path: string, handler: (row: Record) => string): readonly [string, (row: Record) => string] {\n return [path, handler] as const;\n },\n};\n\nexport function rows(row: Record): string {\n return render(\"tokens\", row);\n}\n\napp.get(\"/rows\", rows);\n", + "src/store/rows.ts": "/** One stored row, by column. */\nexport type Row = Record;\n", + "src/store/index.ts": "/** The store's front: what the rest of the shop may import, re-exported whole and by a name of its own. */\nexport * from \"./rows.ts\";\nexport {\n seal as sealRow,\n} from \"./secrets.ts\";\n" }, "language": { "files": [ "src/store/secrets.ts", "src/api/render.ts", "src/app.tsx", - "src/legacy.mjs" + "src/legacy.mjs", + "src/store/rows.ts", + "src/store/index.ts" ], "not": [ "README.md", @@ -48,13 +52,13 @@ "src/__tests__/secrets.test.ts:1", "src/__tests__/secrets.test.ts:2", "src/api/render.ts:1", - "src/api/render.ts:5", + "src/api/render.ts:6", "src/store/secrets.ts:7" ], "grade": "broken", "bypasses": [ "src/api/render.ts:1", - "src/api/render.ts:5" + "src/api/render.ts:6" ], "readings": { "declared": { @@ -68,7 +72,11 @@ "src/store/secrets.ts": [ "SECRET_COLUMNS", "seal" - ] + ], + "src/store/rows.ts": [ + "Row" + ], + "src/store/index.ts": [] }, "imports": [ { @@ -85,6 +93,27 @@ "names": [ "render" ] + }, + { + "file": "src/api/render.ts", + "module": "src/store/rows.ts", + "names": [ + "Row" + ] + }, + { + "file": "src/store/index.ts", + "module": "src/store/rows.ts", + "names": [ + "*" + ] + }, + { + "file": "src/store/index.ts", + "module": "src/store/secrets.ts", + "names": [ + "seal" + ] } ], "interfaces": [ @@ -92,6 +121,7 @@ "from": "src/api", "to": "src/store", "symbols": [ + "Row", "SECRET_COLUMNS", "seal" ] @@ -104,5 +134,19 @@ "rule": "route method" } ] + }, + "reference": { + "files": { + "secrets": "src/store/secrets.ts", + "rows": "src/store/rows.ts", + "render": "src/api/render.ts", + "main": "src/api/routes.ts" + }, + "names": { + "SECRET_COLUMNS": "SECRET_COLUMNS", + "seal": "seal", + "Row": "Row", + "render": "render" + } } } diff --git a/plugins/typescript/plugin.json b/plugins/typescript/plugin.json index 63070904..aa1b3a9b 100644 --- a/plugins/typescript/plugin.json +++ b/plugins/typescript/plugin.json @@ -1,7 +1,7 @@ { "name": "typescript", - "version": "1.10.1", - "pluginApi": 2, + "version": "1.11.0", + "pluginApi": 4, "provides": { "language": "typescript" }, @@ -121,12 +121,15 @@ ] }, "module": "index.ts", + "treeSitter": { + "parser": "tree-sitter-tsx.wasm", + "alternate": "tree-sitter-typescript.wasm", + "queries": "typescript.scm", + "resolve": "typescript-source.ts#TYPESCRIPT_RESOLVE" + }, "syntax": { "entrances": "typescript-entrances.ts#TYPESCRIPT_ENTRANCES", "interfaces": "typescript-scope.ts#TYPESCRIPT_INTERFACES", - "source": "typescript-source.ts#TYPESCRIPT_SOURCE", - "declares": "typescript-interfaces.ts#typescriptDeclares", - "notice": "tsserver.ts#tsserverNotice", - "topLevel": "typescript-top-level.ts#typescriptDeclaresAtTop" + "notice": "tsserver.ts#tsserverNotice" } } diff --git a/plugins/typescript/tree-sitter-tsx.wasm b/plugins/typescript/tree-sitter-tsx.wasm new file mode 100644 index 00000000..4385bb4e Binary files /dev/null and b/plugins/typescript/tree-sitter-tsx.wasm differ diff --git a/plugins/typescript/tree-sitter-typescript.wasm b/plugins/typescript/tree-sitter-typescript.wasm new file mode 100644 index 00000000..3588bb39 Binary files /dev/null and b/plugins/typescript/tree-sitter-typescript.wasm differ diff --git a/plugins/typescript/typescript-scope.ts b/plugins/typescript/typescript-scope.ts index 90bdd789..9fab0994 100644 --- a/plugins/typescript/typescript-scope.ts +++ b/plugins/typescript/typescript-scope.ts @@ -1,29 +1,13 @@ /** - * TypeScript's facts for the component interface reading: which declaration - * lines are types or default exports, and what the word index and the kept - * answers read of a file's imports (component-interfaces.ts reads them - * through INTERFACE_SYNTAX, and kept-answers.ts through its wildcardModules). + * TypeScript's facts for the component interface reading that are no reading + * of its text: its server reads its tsconfig's project whole, so it takes no + * bounds. Which declarations are types and which are default exports, and + * every import and wildcard re-export, are read through its parser (the + * manifest's treeSitter); an interfaces table states none of them. */ -import { specifierCandidates } from "./typescript.ts"; -import type { InterfaceSyntax } from "../../src/plugins/api.ts"; +import type { InterfaceFacts } from "../../src/plugins/api.ts"; -/** A TypeScript import or export list: `import { a as b } from`, `export { a as b }`, `export type { … }`. */ -const TS_LIST = /\b(?:import|export)\s+(?:type\s+)?(?:[A-Za-z_$][\w$]*\s*,\s*)?\{([^}]*)\}/g; -/** A TypeScript default export by name: `export default foo;`, `export = foo`, `export { foo as default }` is read as an alias to "default". */ -const TS_DEFAULT_NAME = /^export\s+(?:default\s+|=\s*)([A-Za-z_$][\w$]*)\s*;?\s*$/gm; -const TS_WILDCARD = /^export\s+(?:type\s+)?\*(?:\s+as\s+[A-Za-z_$][A-Za-z0-9_$]*)?\s+from\s*["']([^"']+)["']/gm; - -/** Interfaces and type aliases are types; `export default` is the default export; the server reads its tsconfig's project, so it takes no bounds. */ -export const TYPESCRIPT_INTERFACES: InterfaceSyntax = { - isTypeDeclaration: (line) => /^(?:export\s+)?(?:declare\s+)?(?:interface|type)\s/.test(line.trim()), - isDefaultExport: (line) => /^export\s+default\s/.test(line.trim()), +export const TYPESCRIPT_INTERFACES: InterfaceFacts = { serverBounds: false, - importLists: (text) => [...text.matchAll(TS_LIST)].map((m) => m[1]!), - defaultNames: (text) => [...text.matchAll(TS_DEFAULT_NAME)].map((m) => m[1]!), - // Every file the specifier may name: without the file list, `./foo.js` is foo.ts in a NodeNext project and foo.js in a JavaScript one. - wildcardModules(file, text) { - return [...text.matchAll(TS_WILDCARD)].flatMap(([, specifier]) => specifierCandidates(file, specifier!)); - }, }; - diff --git a/plugins/typescript/typescript-source.ts b/plugins/typescript/typescript-source.ts index c8f180c4..d857a1cd 100644 --- a/plugins/typescript/typescript-source.ts +++ b/plugins/typescript/typescript-source.ts @@ -1,25 +1,17 @@ /** - * TypeScript's facts for the plain source scan: which top-level names a - * line declares, which names a file imports, and where a relative specifier - * resolves (source.ts reads them through SOURCE_SYNTAX). + * Where a TypeScript or JavaScript import leads: what no parse can say, since + * a module's place is the compiler's rule, not its syntax. What a file + * declares and imports is read through the TSX grammar and typescript.scm + * (the manifest's treeSitter), so this module reads no text. */ import { statSync } from "node:fs"; import { posix, resolve } from "node:path"; -import { isSourceFile, toRelative, type SourceSyntax } from "../../src/plugins/api.ts"; +import { isSourceFile, toRelative, type ModuleResolution } from "../../src/plugins/api.ts"; +import { specifierCandidates } from "./typescript.ts"; -const TS_DECLARATION = /^(export\s+)?(?:default\s+)?(?:declare\s+)?(?:abstract\s+)?(?:async\s+)?(?:function\*?|const|let|var|class|interface|type|enum|namespace)\s+([A-Za-z_$][\w$]*)/; -const TS_NAMED = /import\s+(?:type\s+)?\{([^}]*)\}\s*from\s*["']([^"']+)["']/g; -const TS_DEFAULT = /import\s+(?:type\s+)?([A-Za-z_$][\w$]*)\s*(?:,\s*\{[^}]*\})?\s*from\s*["']([^"']+)["']/g; -const TS_NAMESPACE = /import\s+(?:type\s+)?\*\s+as\s+[A-Za-z_$][\w$]*\s+from\s*["']([^"']+)["']/g; -const TS_SIDE = /(?:^|\n)\s*import\s*["']([^"']+)["']/g; - -/** A declaration is exported when its line says `export`; only a relative specifier names a project file. */ -export const TYPESCRIPT_SOURCE: SourceSyntax = { - declarationOf(line) { - const m = TS_DECLARATION.exec(line); - return m === null ? undefined : { name: m[2]!, exported: m[1] !== undefined }; - }, +/** Only a relative specifier names a project file: the file itself, its TypeScript twin of a .js specifier, or a folder's index. */ +export const TYPESCRIPT_RESOLVE: ModuleResolution = { resolveModule(root, from, specifier, vanished) { if (!specifier.startsWith(".")) return undefined; const joined = posix.normalize(posix.join(posix.dirname(from), specifier)); @@ -36,17 +28,6 @@ export const TYPESCRIPT_SOURCE: SourceSyntax = { } return undefined; }, - importsOf(text, add) { - for (const m of text.matchAll(TS_NAMED)) { - for (const piece of m[1]!.split(",")) { - const cleaned = piece.replace(/^\s*type\s+/, "").trim(); - if (cleaned === "") continue; - const original = cleaned.split(/\s+as\s+/)[0]!.trim(); - add(original, m[2]!); - } - } - for (const m of text.matchAll(TS_DEFAULT)) add("default", m[2]!); - for (const m of text.matchAll(TS_NAMESPACE)) add(undefined, m[1]!); - for (const m of text.matchAll(TS_SIDE)) add(undefined, m[1]!); - }, + // Every file a wildcard re-export's specifier may name: without the file list, `./foo.js` is foo.ts in a NodeNext project and foo.js in a JavaScript one. + modulePaths: (from, specifier) => specifierCandidates(from, specifier), }; diff --git a/plugins/typescript/typescript.scm b/plugins/typescript/typescript.scm new file mode 100644 index 00000000..2a1bbce6 --- /dev/null +++ b/plugins/typescript/typescript.scm @@ -0,0 +1,156 @@ +; TypeScript's and JavaScript's imports and top-level declarations, as the capture names Coherence reads (docs/plugins.md). +; The parsers beside it are tree-sitter-typescript 0.23.2's two grammars built with a patch (grammars/tree-sitter-typescript, language ABI 15): +; tree-sitter-tsx.wasm reads every file the plugin's pattern takes (.ts, .tsx, .mts, .cts, .js, .jsx, .mjs, .cjs), since it reads JSX, +; which the TypeScript grammar refuses (3,196 of PostHog's 3,510 .tsx files); tree-sitter-typescript.wasm is its alternate, read where the +; TSX tree errs and the TypeScript tree's errors cover less: an old-style cast (row) is a JSX tag to TSX, one that swallows every declaration +; after it, and a cast to TypeScript. Both compile these queries, so they name no JSX node: a constant whose value is JSX declares unknown. + +; import x from "m" -- the module's default export, under a name of the file's own +(import_statement + (import_clause (identifier) @import.default) + source: (string (string_fragment) @import.from)) @import + +; import { a, b as c, type d } from "m", import type { e } from "m" -- one match per imported name +(import_statement + (import_clause (named_imports (import_specifier name: (_) @import.name !alias))) + source: (string (string_fragment) @import.from)) @import +(import_statement + (import_clause (named_imports (import_specifier name: (_) @import.name alias: (_) @import.alias))) + source: (string (string_fragment) @import.from)) @import + +; import * as ns from "m", import "m", import x = require("m") -- the whole module; a namespace's name is no rename of a name the module declares +(import_statement + (import_clause (namespace_import)) + source: (string (string_fragment) @import.module)) @import +(import_statement . source: (string (string_fragment) @import.module)) @import +(import_statement (import_require_clause source: (string (string_fragment) @import.module))) @import + +; export { a, b as c } from "m" -- a re-export: the file imports each name it re-exports +(export_statement + (export_clause (export_specifier name: (_) @import.name !alias)) + source: (string (string_fragment) @import.from)) @import +(export_statement + (export_clause (export_specifier name: (_) @import.name alias: (_) @import.alias)) + source: (string (string_fragment) @import.from)) @import + +; export * from "m" -- every name the module exports, and the module whole, which the file depends on as a whole-module import does +(export_statement "*" @import.glob source: (string (string_fragment) @import.from)) @import +(export_statement "*" source: (string (string_fragment) @import.module)) @import + +; export * as ns from "m" -- the module whole, under one name: no name of it is spread into the file's exports +(export_statement (namespace_export) source: (string (string_fragment) @import.module)) @import + +; export default foo, export = foo, export { foo as default } -- a name exported as the module's default +(program (export_statement "default" value: (identifier) @default)) +(program (export_statement "=" (identifier) @default)) +((program (export_statement (export_clause (export_specifier name: (identifier) @default alias: (identifier) @_alias)) !source)) + (#eq? @_alias "default")) + +; a function or class at the top level declares a body, exported or not, the default export or not, declared ambient or not +(program + [(function_declaration name: (identifier) @name) + (generator_function_declaration name: (identifier) @name) + (function_signature name: (identifier) @name) + (class_declaration name: (type_identifier) @name) + (abstract_class_declaration name: (type_identifier) @name)] @declaration.body) +(program + (export_statement + "default"? @default + declaration: [(function_declaration name: (identifier) @name) + (generator_function_declaration name: (identifier) @name) + (function_signature name: (identifier) @name) + (class_declaration name: (type_identifier) @name) + (abstract_class_declaration name: (type_identifier) @name)] @declaration.body) @exported) +(program + (ambient_declaration + [(function_signature name: (identifier) @name) + (class_declaration name: (type_identifier) @name) + (abstract_class_declaration name: (type_identifier) @name)] @declaration.body)) +(program + (export_statement + declaration: (ambient_declaration + [(function_signature name: (identifier) @name) + (class_declaration name: (type_identifier) @name) + (abstract_class_declaration name: (type_identifier) @name)] @declaration.body)) @exported) + +; an interface or a type alias declares a type +(program [(interface_declaration name: (type_identifier) @name) (type_alias_declaration name: (type_identifier) @name)] @declaration.type) +(program (export_statement "default"? @default declaration: [(interface_declaration name: (type_identifier) @name) (type_alias_declaration name: (type_identifier) @name)] @declaration.type) @exported) +(program (ambient_declaration [(interface_declaration name: (type_identifier) @name) (type_alias_declaration name: (type_identifier) @name)] @declaration.type)) +(program (export_statement declaration: (ambient_declaration [(interface_declaration name: (type_identifier) @name) (type_alias_declaration name: (type_identifier) @name)] @declaration.type)) @exported) + +; an enum or a namespace declares a value +(program [(enum_declaration name: (identifier) @name) (internal_module name: (identifier) @name)] @declaration.value) +(program (export_statement declaration: [(enum_declaration name: (identifier) @name) (internal_module name: (identifier) @name)] @declaration.value) @exported) +(program (ambient_declaration [(enum_declaration name: (identifier) @name) (internal_module name: (identifier) @name)] @declaration.value)) +(program (export_statement declaration: (ambient_declaration [(enum_declaration name: (identifier) @name) (internal_module name: (identifier) @name)] @declaration.value)) @exported) + +; const, let or var: each name bound declares what its value is -- a function or class a body; a literal, an object or an instance a value, +; asserted to a type or not, twice at most (x as unknown as T, [..] as const satisfies T); +; no value at all a value; anything else (a call's result, another name) unknown, since it may hold a function. The unknown pattern matches +; every value, and a declaration whose value a pattern above it knows is read as that (syntax-trees.ts). +(program (_ (variable_declarator name: (identifier) @name value: [(arrow_function) (function_expression) (generator_function) (class)]) @declaration.body)) +(program (export_statement declaration: (_ (variable_declarator name: (identifier) @name value: [(arrow_function) (function_expression) (generator_function) (class)]) @declaration.body)) @exported) +(program + (_ (variable_declarator + name: (identifier) @name + value: [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (regex) (new_expression) (unary_expression) + [(as_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)]) (satisfies_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)])] + [(as_expression . [(as_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)]) (satisfies_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)])]) (satisfies_expression . [(as_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)]) (satisfies_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)])])]]) @declaration.value)) +(program + (export_statement + declaration: (_ (variable_declarator + name: (identifier) @name + value: [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (regex) (new_expression) (unary_expression) + [(as_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)]) (satisfies_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)])] + [(as_expression . [(as_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)]) (satisfies_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)])]) (satisfies_expression . [(as_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)]) (satisfies_expression . [(object) (array) (string) (template_string) (number) (true) (false) (null) (undefined) (new_expression)])])]]) @declaration.value)) @exported) +((program (_ (variable_declarator name: (identifier) @name value: (call_expression function: (identifier) @_callee)) @declaration.value)) + (#eq? @_callee "Symbol")) +((program (export_statement declaration: (_ (variable_declarator name: (identifier) @name value: (call_expression function: (identifier) @_callee)) @declaration.value)) @exported) + (#eq? @_callee "Symbol")) +; arithmetic, a comparison or a concatenation (10 * 60 * 1000) is a value; a || b, a && b and a ?? b may be either operand, a function among them +((program (_ (variable_declarator name: (identifier) @name value: (binary_expression operator: _ @_operator)) @declaration.value)) + (#not-any-of? @_operator "||" "&&" "??")) +((program (export_statement declaration: (_ (variable_declarator name: (identifier) @name value: (binary_expression operator: _ @_operator)) @declaration.value)) @exported) + (#not-any-of? @_operator "||" "&&" "??")) +(program (_ (variable_declarator name: (identifier) @name !value) @declaration.value)) +(program (export_statement declaration: (_ (variable_declarator name: (identifier) @name !value) @declaration.value)) @exported) +(program (ambient_declaration (_ (variable_declarator name: (identifier) @name) @declaration.value))) +(program (export_statement declaration: (ambient_declaration (_ (variable_declarator name: (identifier) @name) @declaration.value))) @exported) +(program (_ (variable_declarator name: (identifier) @name value: (_)) @declaration.unknown)) +(program (export_statement declaration: (_ (variable_declarator name: (identifier) @name value: (_)) @declaration.unknown)) @exported) + +; a destructuring binds each name it takes, two patterns deep (export const { handlers: { GET, POST }, auth } = NextAuth(...)): +; bound at the top level, where a framework finds the name, not declared; braces that assign nothing bind nothing +(program + (_ (variable_declarator + name: [(object_pattern [(shorthand_property_identifier_pattern) @name (pair_pattern value: (identifier) @name) (object_assignment_pattern left: (shorthand_property_identifier_pattern) @name) (pair_pattern value: (assignment_pattern left: (identifier) @name)) (rest_pattern (identifier) @name)]) + (object_pattern (pair_pattern value: (object_pattern [(shorthand_property_identifier_pattern) @name (pair_pattern value: (identifier) @name) (object_assignment_pattern left: (shorthand_property_identifier_pattern) @name) (pair_pattern value: (assignment_pattern left: (identifier) @name)) (rest_pattern (identifier) @name)]))) + (object_pattern (pair_pattern value: (array_pattern [(identifier) @name (assignment_pattern left: (identifier) @name) (rest_pattern (identifier) @name)]))) + (array_pattern [(identifier) @name (assignment_pattern left: (identifier) @name) (rest_pattern (identifier) @name)]) + (array_pattern (object_pattern [(shorthand_property_identifier_pattern) @name (pair_pattern value: (identifier) @name) (object_assignment_pattern left: (shorthand_property_identifier_pattern) @name) (pair_pattern value: (assignment_pattern left: (identifier) @name)) (rest_pattern (identifier) @name)])) + (array_pattern (array_pattern [(identifier) @name (assignment_pattern left: (identifier) @name) (rest_pattern (identifier) @name)]))] + value: (_)) @bound)) +(program + (export_statement + declaration: (_ (variable_declarator + name: [(object_pattern [(shorthand_property_identifier_pattern) @name (pair_pattern value: (identifier) @name) (object_assignment_pattern left: (shorthand_property_identifier_pattern) @name) (pair_pattern value: (assignment_pattern left: (identifier) @name)) (rest_pattern (identifier) @name)]) + (object_pattern (pair_pattern value: (object_pattern [(shorthand_property_identifier_pattern) @name (pair_pattern value: (identifier) @name) (object_assignment_pattern left: (shorthand_property_identifier_pattern) @name) (pair_pattern value: (assignment_pattern left: (identifier) @name)) (rest_pattern (identifier) @name)]))) + (object_pattern (pair_pattern value: (array_pattern [(identifier) @name (assignment_pattern left: (identifier) @name) (rest_pattern (identifier) @name)]))) + (array_pattern [(identifier) @name (assignment_pattern left: (identifier) @name) (rest_pattern (identifier) @name)]) + (array_pattern (object_pattern [(shorthand_property_identifier_pattern) @name (pair_pattern value: (identifier) @name) (object_assignment_pattern left: (shorthand_property_identifier_pattern) @name) (pair_pattern value: (assignment_pattern left: (identifier) @name)) (rest_pattern (identifier) @name)])) + (array_pattern (array_pattern [(identifier) @name (assignment_pattern left: (identifier) @name) (rest_pattern (identifier) @name)]))] + value: (_)) @bound))) + +; an export list, with or without a from, binds each name it exports, under the name it exports (export { handle as GET }): +; the re-exporting file is where a framework finds the name, and the source is not followed (d-7155e46f) +(program (export_statement (export_clause (export_specifier name: (_) @name !alias))) @bound) +(program (export_statement (export_clause (export_specifier alias: (_) @name))) @bound) +(program (export_statement (namespace_export (identifier) @name)) @bound) + +; A reserved word read as a name: valid TypeScript binds none, but for an import's or an export's name (export { x as default }, +; export * as default), so in a tree with no error this is the grammar misreading the text, and orient says so (misreadNotice). +; Over 171,579 files of PostHog's and of node_modules, error-free trees held such a name under those three parents alone. +((identifier) @misread + (#match? @misread "^(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|if|import|in|instanceof|new|null|return|super|switch|this|throw|true|try|typeof|var|void|while|with)$") + (#not-parent-type? @misread import_specifier export_specifier namespace_export)) diff --git a/plugins/typescript/typescript.ts b/plugins/typescript/typescript.ts index 00d4e42d..53333032 100644 --- a/plugins/typescript/typescript.ts +++ b/plugins/typescript/typescript.ts @@ -37,6 +37,7 @@ import { type Definition, type Ladder, type LanguageAdapter, + type ServerSymbol, type Position, type Range, type ReferenceSite, @@ -103,6 +104,8 @@ interface DocumentSymbol { range: Range; selectionRange: Range; children?: DocumentSymbol[]; + /** Set where the server answered a flat SymbolInformation list naming the symbol's container: no top-level symbol. */ + nested?: true; } interface SymbolInformation { @@ -395,6 +398,11 @@ export class TypeScriptAdapter implements LanguageAdapter { this.documents.delete(file); } + /** The file's top-level symbols as the server reports them: the independent account plugin check and plugin calibrate hold the text readings to. */ + async topLevelSymbols(file: string): Promise { + return (await this.documentSymbols(file)).filter((s) => s.nested !== true).map((s) => ({ name: s.name, line: s.selectionRange.start.line + 1, kind: s.kind })); + } + private async documentSymbols(file: string): Promise { const cached = this.symbolCache.get(file); if (cached !== undefined) return cached; @@ -408,7 +416,7 @@ export class TypeScriptAdapter implements LanguageAdapter { this.open(file); const result = await client.request("textDocument/documentSymbol", { textDocument: { uri: this.uri(file) } }); const symbols: DocumentSymbol[] = (result ?? []).map((s) => - "location" in s ? { name: s.name, kind: s.kind, range: s.location.range, selectionRange: s.location.range } : s, + "location" in s ? { name: s.name, kind: s.kind, range: s.location.range, selectionRange: s.location.range, ...(s.containerName ? { nested: true as const } : {}) } : s, ); this.symbolCache.set(file, symbols); return symbols; diff --git a/src/adapters/Adapters.spec.md b/src/adapters/Adapters.spec.md index 41204701..e8a30ab7 100644 --- a/src/adapters/Adapters.spec.md +++ b/src/adapters/Adapters.spec.md @@ -125,7 +125,7 @@ The language adapter seam: how to ask a language's server for definitions, refer refuted: joined pytest names as a regex -> "pytest's JUnit report reads as the jest shape, and -k names join with or" went red in python.test.ts; restored, green (2026-09-17) kinds: none - server located or a reason: The language server binary is resolved by the package resolver from the adopter's project first, then from Coherence's own module, then found on PATH, and its absence is a reason naming each place looked, never a crash. - protects: SERVER_BIN in typescript.ts + protects: SERVER_BIN in plugins/typescript/typescript.ts chokepoint: plugins/typescript/typescript.ts over: the adopter's project, Coherence's own module, and every folder on PATH via: the language server binary is found (the adapter's precondition) @@ -163,6 +163,14 @@ The language adapter seam: how to ask a language's server for definitions, refer because: agents work in git worktrees under .claude/worktrees, inside the main checkout, and each worktree's copy of a file reads to a language server as more of the project; a reference in an agent's copy of verbs.ts graded attributed writes broken in the main checkout, the edit hook reported the same false bypasses to several agents, and the Structure map shown to reviewers carried the false broken (conjecture c-16d2f394, resolution rs-b4cf50f6). Git's own ignore rules already say what is not the project's, and a folder holding a .git is another checkout even when git cannot follow its gitdir, so both halves are one rule crossing: instrument -> reading kinds: none +- a reading is handed only files it can open: Every enumeration of the project's files (projectFiles, projectFilesUnder, projectFilesEnding) passes one test, isFileOnDisk: a regular file, or a link to one; never a folder, a pipe, a socket or a device, which a read waits on forever or reads without end, and never a link to one of those or to nothing; and a change (keepProjectFiles) keeps every path it names but a folder, a pipe, a socket, a device or a link to a pipe, a socket or a device, so a tracked link relinked to a folder or left dangling, and a tracked file an edit deleted, are each still a changed path. + over: a project holding a regular file, a link to it, a pipe, a link to the pipe, a folder holding a file, a link to the folder and a link to nothing, in a repository and out of one; and keepProjectFiles over each of those paths and a committed file since deleted + via: a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one + because: the walk kept every path that was not a folder, so a pipe a repository commits, or a link to one, was handed to every reading of the project, which waited on it forever; the warm-up a session start runs unasked hung on one (the blind review of ca263d3), and one test every enumeration passes leaves no walk that can hand one over (the owner's direction to leave each reviewed defect unrepresentable (d-262d3cd3)); the first fix kept from a change only what a reading could open, so a tracked link relinked to another folder or left dangling dropped out of the working change, which economy --changed read as 3 changed paths where git said 5 (the blind review of 887abd8) + refuted: took every path but a folder for a project file (isFileOnDisk in src/adapters/project-files.ts) -> "a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one" went red in project-files.test.ts on its own assertion (in a repository: a regular file, and a link to one, alone); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: kept every path an edit names but a folder (isOtherOnDisk in src/adapters/project-files.ts) -> "a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one" went red in project-files.test.ts on its own assertion (a path an edit names is kept only where it can be opened); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: kept from a change only what a reading can open, dropping a link to a folder or to nothing (isOtherOnDisk in src/adapters/project-files.ts) -> "a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one" went red in project-files.test.ts on its own assertion (a path an edit names is kept unless a read of it would wait or it is a folder, a deleted file among them); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none - a folder is left out only by a named rule: Every walk of the project reads the project's files that one rule (exclusionOf in project-files.ts) leaves in, narrowed only by kind, and that rule leaves a folder out only for a reason it names: the config's ignore list, a host's folder, a hidden folder, a dependency install, an interpreter's cache, a virtual environment, or Cargo's build folder (a target beside a Cargo.toml); never for its name alone, and what it leaves out plus what it reads is exactly the project's files. over: every walker of the project (the spec walker, the economy's source files, both adapters' file walks, the Scope reading's bounds and entrance detection, the vocabulary check's corpus) over a project holding code in folders named public, dist, build and target beside a folder of each rule via: every walk reads what the one rule leaves in: a folder is left out only by a named rule, never by its name alone @@ -177,12 +185,12 @@ The language adapter seam: how to ask a language's server for definitions, refer crossing: project-source -> reading refuted: dropped the exact-path match from underIgnored in project-files.ts, so an ignore entry naming a file by its path left it in the bounded listing, the vocabulary corpus and an edit's reading -> "the ignore list names a file by its path: every walk, the vocabulary corpus, an edit's reading and coverage leave it out, and a file elsewhere by the same name is read" went red in src/adapters/ignore-files.test.ts on its own assertion; restored byte for byte, green batched and alone (2026-10-08) kinds: none -- entrance detection follows listed rules: The entrances the reading detects come only from the rules its language lists (CANDIDATE_RULES: for TypeScript, server functions, wrapped exports, server routes, route handlers, request proxies, page routes, server actions, route tables, route methods, package bins, package scripts and top-level scripts; for Python, URL patterns, viewsets, route decorators, management commands, tasks, console scripts and scripts; for Rust, binaries, build scripts, route attributes, route registrations and foreign exports), each carrying its rule and why it matched, never from a test file, a path inside a string, an include(), a TanStack Start file route without server handlers or a script another file imports; a detected entrance records the declared handlers and guards its own statement calls, bound in its file, one level into the file's own helpers. - over: every rule the three languages list over a TypeScript, a Python and a Rust project holding each shape and each near miss (a doc example's route, a route in a #[cfg(test)] module), and a wrapper a file neither imports nor declares +- entrance detection follows listed rules: The entrances the reading detects come only from the rules its language lists (CANDIDATE_RULES: for TypeScript, server functions, wrapped exports, server routes, route handlers, request proxies, page routes, server actions, route tables, route methods, package bins, package scripts and top-level scripts; for Python, URL patterns, viewsets, route decorators, management commands, tasks, console scripts and scripts; for Rust, binaries, examples, build scripts, route attributes, route registrations and foreign exports, a wasm-bindgen or UniFFI impl's exported methods named Type::method among them), each carrying its rule and why it matched, never from a test file, a path inside a string, an include(), a TanStack Start file route without server handlers or a script another file imports; a detected entrance records the declared handlers and guards its own statement calls, bound in its file, one level into the file's own helpers. + over: every rule the three languages list over a TypeScript, a Python and a Rust project holding each shape and each near miss (a doc example's route, a route in a #[cfg(test)] module, an extern block's import, a private, pub(crate), skipped or plain impl's method, a trait impl wasm-bindgen cannot export, an example's helper file and a tests.rs), and a wrapper a file neither imports nor declares via: entrance detection because: c-3760638e: the coverage of the declared entrances is only as honest as what they are measured against, so detection is a short list of shapes a framework or runner fixes, each explained where it is shown, and precision wins over recall; what the rules cannot see is said beside the counts. A wrapper's namesake counted as a registration would group entrances that are not registered through it. A URL pattern or a registration is read across lines: a per-line scan missed every path( call whose route sat on the next line, and three of billing's routes were declared by hand (df-8f004647) crossing: project-source -> reading - refuted: counted a wrapper call as a registration without checking the file imports or declares it, in throughOf -> the totality oracle went red; restored, green (2026-09-28); matched a URL pattern only when its route sat on the line of path(, as the per-line scan did -> the Python rules test went red; restored, green (2026-10-06); detected an entrance inside a #[cfg(test)] module, dropping the test-range filter from rust-entrances.ts -> the Rust rules test went red on its own assertion; restored from a copy, byte for byte, green (2026-10-23) + refuted: counted a wrapper call as a registration without checking the file imports or declares it, in throughOf -> the totality oracle went red; restored, green (2026-09-28); matched a URL pattern only when its route sat on the line of path(, as the per-line scan did -> the Python rules test went red; restored, green (2026-10-06); detected an entrance inside a #[cfg(test)] module, dropping the test-range filter from rust-entrances.ts -> the Rust rules test went red on its own assertion; restored from a copy, byte for byte, green (2026-10-23; read a #[wasm_bindgen] impl as exporting none of its methods, in foreignExports (rust-entrances.ts) -> the Rust rules test for wasm-bindgen, UniFFI and examples went red on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-24) kinds: none - the request proxy is an entrance: The proxy a Next.js proxy.ts exports, or the middleware a middleware.ts exports, at the project root or under src/, is detected as a request proxy, whether declared, named in an export list or re-export, or the file's default export; a helper beside it, a namesake in another folder and a test file are not. over: a declared proxy with a helper and a config beside it, a middleware re-exported under an alias, a default-exported middleware, a proxy under lib/ and one in a test file @@ -369,17 +377,23 @@ The language adapter seam: how to ask a language's server for definitions, refer because: a hint written as the file's whole path also took a fixture's copy under an ignored folder, so the name read as declared in two places and the chokepoint was not checked (the blind Swift plugin session, 2026-10-22); every bundled adapter carried the same match refuted: made hintedFiles take every file ending with the hint even when one is at that exact path, as every adapter did (adapter.ts) -> "a file hint names the file at that path when there is one, else every file ending with it" went red in adapter.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-23) kinds: none -- a Rust line declares its items: The plain scan reads a Rust line's top-level item (fn, struct, enum, union, trait, type, const, static, mod or macro_rules!) under any visibility and qualifier, exported when pub in any form; an impl, a use, an extern crate and an indented item declare nothing, and the interface map reads a fn, struct, enum or union as a body, a trait or type alias as a type, a const or static as a value. - over: every item keyword with pub, pub(crate), pub(in path), const, async, unsafe and raw identifiers, and the lines that declare nothing - via: a Rust line declares an item at column zero under any visibility and qualifier, exported when pub in any form; an impl, a use or an indented item declares nothing - because: the Rust plugin filled no text slot, so mass, the economy and the Structure reading named Rust not read: a Rust project had chokepoint checks and nothing else (a session read the plugin as doing almost nothing, 2026-10-23) - refuted: read every Rust item as exported (rust-source.ts) -> "a Rust line declares an item at column zero under any visibility and qualifier, exported when pub in any form; an impl, a use or an indented item declares nothing" went red in rust-source.test.ts; restored from a copy, byte for byte, green (2026-10-23) - kinds: none -- a Rust use is read in code alone: A use tree is read leaf by leaf through nested braces, renames, self and globs, and a use or mod inside a comment, a string (one continued past a line end included) or a raw string is never read. - over: nested braces, an alias, self, a glob, a pub(crate) use, a leading ::, a line and a block comment, a string continued with a backslash, and a raw string holding a quote - via: a use tree is read leaf by leaf through nested braces, renames, self and globs, and nothing in a comment or a string is read - because: axum's doc examples are use lines in comments, and a string continued past a line end once threw the quote pairing off for the rest of the file, so its comments were read as code - refuted: scanned use trees with strings left whole (rust-source.ts) -> "a use tree is read leaf by leaf through nested braces, renames, self and globs, and nothing in a comment or a string is read" went red in rust-source.test.ts; restored from a copy, byte for byte, green (2026-10-23) +- a Rust file declares its top-level items: Rust's parser and rust.scm read a file's top-level items (fn, struct, enum, union, trait, type, const, static, mod or macro_rules!) under any visibility and qualifier, an attribute on the same line included, exported when pub in any form and named as written (a raw identifier keeps its r#, as rust-analyzer names it); an impl, a use, an extern crate, an item inside another and one inside a string declare nothing; and one parse says what each declares: a fn, struct, enum, union or macro a body, a trait or type alias a type (to the interface map and declares alike), a const or static a value, a mod unknown. + over: every item keyword with pub, pub(crate), pub(in path), const, async, unsafe, a raw identifier and an attribute on the item's line, and the lines that declare nothing, an item inside a string among them + via: a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing + because: the Rust plugin filled no text slot, so mass, the economy and the Structure reading named Rust not read: a Rust project had chokepoint checks and nothing else (a session read the plugin as doing almost nothing, 2026-10-23); its line reader then missed an item after an attribute on its line, read items out of strings, and said a trait was a type to declares and not to the interface map + refuted: dropped the @exported capture from rust.scm's fn pattern, so a pub fn reads as private (plugins/rust/rust.scm) -> "a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing" went red in rust-source.test.ts on its own assertion (seal read as private); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a Rust use is read in code alone: Rust's parser reads a use tree leaf by leaf through nested braces (a group's path prefixing every leaf inside it, to any depth), renames, self and globs, each path both as an item of its module and as the module itself (only the reading that resolves is kept), and a use or mod inside a comment, a string (one continued past a line end included) or a raw string is never read. + over: nested braces, an alias, self, a glob in a group, a pub(crate) use, a leading ::, a line and a block comment, a string continued with a backslash, and a raw string holding a quote + via: a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read + because: axum's doc examples are use lines in comments, and a string continued past a line end once threw the quote pairing off for the rest of the file, so its comments were read as code; a capture reads one node's text, so a path a group spells in pieces is only whole where the core joins its prefixes + refuted: dropped rust.scm's prefix pattern for a group's path, so a leaf in a nested group is read without the paths over it (plugins/rust/rust.scm) -> "a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read" went red in rust-source.test.ts on its own assertion (Row from store for Row from crate::store); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a Rust use in an inline module is read from that module: A use inside an inline module (mod tests { … }) is read from that module, not from its file's: each super leaves an inline module before it leaves the file's, a path still inside one (use super::* in a test module, self::) leads to no other file, and a bare path there names a crate of the workspace; a glob of the file's own module keys no file in the word index. + over: use super::*, super::super, crate::, a workspace crate, self:: and a bare path in a #[cfg(test)] module, and super::super::super from a module inside it + via: a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate + because: the line reader read every use as written at the file's top, so each use super::* in a test module (678 of PostHog's Rust files) imported the file's parent module whole, a dependency the code does not have, and super::super resolved one module too high + refuted: dropped rust.scm's inline mod prefix, so a use in a test module is read as though written at the file's top (plugins/rust/rust.scm) -> "a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate" went red in rust-source.test.ts on its own assertion (* <- src/lib.rs read from use super::*); restored from a copy, byte for byte, green batched and alone (2026-10-26) kinds: none - a Rust path resolves to the project's own files: A use path resolves to the module file it names by the crate's folder layout (crate, self, super and a module of the file's own; a.rs or a/mod.rs), into another crate of the workspace by its package name, from a root a Cargo.toml names at a path of its own, and only under the file's exact spelling; a path into a crate outside the workspace resolves to nothing. over: crate, self, super, super::super, a bare module path, a glob, a workspace crate spelled with - and with a leading ::, a [[bin]] root outside src, a module named like an item, and an external crate diff --git a/src/adapters/adapter.ts b/src/adapters/adapter.ts index aa33767c..0e8d44f4 100644 --- a/src/adapters/adapter.ts +++ b/src/adapters/adapter.ts @@ -235,6 +235,20 @@ export interface LanguageAdapter { close(): Promise; /** The language server's process id while it runs, so a reading can bound that server's memory; absent where the adapter cannot say. */ serverPid?(): number | undefined; + /** + * The symbols the language server says a file declares at its top level, + * each with its one-based line and LSP symbol kind: the independent account + * the text readings are calibrated against (plugin check's server agrees + * duty, coherence plugin calibrate). Absent where the adapter cannot ask. + */ + topLevelSymbols?(file: string): Promise; +} + +/** A symbol as the language server reports it: its name, the one-based line its name stands on, and its LSP SymbolKind. */ +export interface ServerSymbol { + name: string; + line: number; + kind: number; } /** diff --git a/src/adapters/entrance-candidates.test.ts b/src/adapters/entrance-candidates.test.ts index 48e64fba..056fe639 100644 --- a/src/adapters/entrance-candidates.test.ts +++ b/src/adapters/entrance-candidates.test.ts @@ -236,6 +236,114 @@ describe("entrance detection", () => { } }); + test("the Rust rules detect what wasm-bindgen and UniFFI export (an exported impl's pub methods and constructor as Type::method, a start fn) and an example's main at Cargo's default paths; never an extern block's imports, a private or plain impl's method, a trait impl wasm-bindgen cannot export, a test module or a tests.rs", () => { + const { root, files, remove } = project({ + "Cargo.toml": '[package]\nname = "viewer"\n', + "src/lib.rs": [ + "use wasm_bindgen::prelude::*;", + "", + "#[wasm_bindgen]", + 'extern "C" {', + " #[wasm_bindgen(js_namespace = console)]", + " fn log(s: &str);", + "}", + "", + "#[wasm_bindgen(start)]", + "fn boot() {}", + "", + "/// The viewer: { a brace in a doc comment opens nothing.", + "#[wasm_bindgen]", + "pub struct Viewer {", + " frames: u32,", + "}", + "", + "#[wasm_bindgen]", + "impl Viewer {", + " #[wasm_bindgen(constructor)]", + " pub fn new() -> Viewer {", + ' let close = "}";', + " Viewer { frames: 0 }", + " }", + "", + " /// Draws a frame.", + " pub fn draw(&mut self) {", + " fn nested() {}", + " if self.frames > 0 {", + " nested();", + " }", + " }", + "", + " #[wasm_bindgen(getter)]", + " pub fn frames(&self) -> u32 {", + " self.frames", + " }", + "", + " #[wasm_bindgen(skip)]", + " pub fn skipped(&self) {}", + " fn private(&self) {}", + " pub(crate) fn crate_only(&self) {}", + "}", + "", + "impl Viewer {", + " pub fn not_exported(&self) {}", + "}", + "", + "#[wasm_bindgen]", + "impl Default for Viewer {", + " fn default() -> Self { Viewer::new() }", + "}", + "", + "#[uniffi::export]", + "pub fn open_store(path: String) -> u32 { 0 }", + "", + "#[uniffi::export]", + "impl Store {", + " #[uniffi::constructor]", + " pub fn new() -> Self { Store }", + " pub fn rows(&self) -> u32 { 0 }", + " fn private(&self) {}", + "}", + "", + "#[uniffi::export]", + "impl Shape for Ring {", + " fn area(&self) -> f32 { 0.0 }", + "}", + "", + "#[cfg(test)]", + "mod tests {", + " #[wasm_bindgen]", + " impl Fake {", + " pub fn fake(&self) {}", + " }", + "}", + ].join("\n"), + "src/scene/tests.rs": '#[no_mangle]\npub extern "C" fn only_for_tests() {}\n', + "examples/demo.rs": "fn main() {}\n", + "examples/tour/main.rs": "fn main() {}\n", + "examples/tour/helper.rs": "fn main() {}\n", + "src/examples/inner.rs": "fn main() {}\n", + }); + try { + const found = detectEntranceCandidates(root, { language: "rust", files, wrappers: [], testFolders: [] }); + const rules = new Set(CANDIDATE_RULES["rust"]!.map((r) => r.rule)); + for (const c of found) assert.ok(rules.has(c.rule) && c.why.length > 0, `${c.rule} is a listed rule and says why`); + const names = (rule: string): string[] => found.filter((c) => c.rule === rule).map((c) => `${c.file}:${c.line} ${c.symbol}`).sort(); + assert.deepEqual( + names("foreign export"), + ["src/lib.rs:20 Viewer::new", "src/lib.rs:27 Viewer::draw", "src/lib.rs:34 Viewer::frames", "src/lib.rs:54 open_store", "src/lib.rs:59 Store::new", "src/lib.rs:61 Store::rows", "src/lib.rs:67 Ring::area", "src/lib.rs:9 boot"], + "an exported impl's methods by Type::method at their attributes; a skipped, private, pub(crate), plain impl's or wasm trait impl's method, a nested fn, an extern block's import and a test module's are none; a tests.rs is a test file", + ); + assert.match(found.find((c) => c.symbol === "boot")!.why, /wasm_bindgen\(start\)/); + assert.match(found.find((c) => c.symbol === "Viewer::new")!.why, /constructor/); + assert.match(found.find((c) => c.symbol === "Ring::area")!.why, /uniffi::export/); + assert.deepEqual(names("example"), ["examples/demo.rs:1 main", "examples/tour/main.rs:1 main"], "an example's main at Cargo's default paths alone: a helper beside it and a module's examples folder under src/ are none"); + assert.deepEqual(found.filter((c) => c.rule === "example").map((c) => entranceName(c)).sort(), ["example demo", "example tour"]); + assert.deepEqual(names("binary"), [], "an example is no binary"); + } finally { + remove(); + } + }); + test("the Go rules detect a command's main, a handler registered on a ServeMux, a route on a router the file imports, and a cgo export; a doc comment, a string, an inline handler, a test file and a router method in a file that imports no router detect nothing", () => { const { root, files, remove } = project({ "coherence.config.json": JSON.stringify({ language: "go", plugins: { go: "bundled" } }), diff --git a/src/adapters/go-source.test.ts b/src/adapters/go-source.test.ts index bb6c9c74..d244ba54 100644 --- a/src/adapters/go-source.test.ts +++ b/src/adapters/go-source.test.ts @@ -1,9 +1,10 @@ /** - * The Go plugin's text scans (plugins/go/go-source.ts, go-scope.ts, - * go-interfaces.ts, go-top-level.ts): what a line declares, alone or in a - * grouped block, what a file imports and which of the package's files each - * name it uses comes from, where an import path resolves by go.mod and - * go.work, and that mass reads Go as it reads the other languages. + * The Go plugin's readings of its text through Go's parser and go.scm (the + * manifest's treeSitter) and plugins/go/go-source.ts: what a file declares + * at the package level and what each declares, what a file imports and + * which of the package's files each name it uses comes from, where an + * import path resolves by go.mod and go.work, and that mass reads Go as it + * reads the other languages. */ import assert from "node:assert/strict"; @@ -15,10 +16,8 @@ import { readEnforcementConfig } from "../enforcement/config.ts"; import { computeMass, formatMass } from "../economy/mass.ts"; import { declarationsOf, importsOf } from "../economy/source.ts"; import { declares } from "../observation/interfaces.ts"; -import { isTypeDeclaration } from "../readings/scope/component-interfaces.ts"; -import { GO_INTERFACES } from "../../plugins/go/go-scope.ts"; -import { codeOnly, importsIn, packageNameOf, uncommented } from "../../plugins/go/go-source.ts"; -import { goDeclaresAtTop } from "../../plugins/go/go-top-level.ts"; +import { parsedOf, syntaxOf } from "../plugins/languages.ts"; +import { codeOnly, packageNameOf, uncommented } from "../../plugins/go/go-source.ts"; const madeFolders: string[] = []; after(() => { @@ -43,6 +42,9 @@ before(() => { project({}); }); +/** Go's topLevel slot, derived from its parser. */ +const atTop = (text: string, name: string): boolean => parsedOf("go", "topLevel")!(text, name); + const DECLARATIONS = [ "package store", "", @@ -84,6 +86,9 @@ const DECLARATIONS = [ "*/", "var _ Reader = (*Entry)(nil)", "var Ready bool", + "var Sum = 1 + 2", + "var Once = func() int { return 1 }()", + "var β, Γ = `raw`, -1", "const Version = \"1\"", "type Count int", "type Arr [4]int", @@ -96,10 +101,17 @@ const DECLARATIONS = [ "\treturn inner", "}", "", + "var generated = `", + "package fake", + "func Fake() {}", + "`", + "", + "func After() {}", + "", "func main() { fmt.Println(Version) }", ].join("\n"); -test("a Go line declares a package-level func, type, var or const at column zero, or a member of a grouped block one level in; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string declare nothing", () => { +test("a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing", () => { const found = declarationsOf(DECLARATIONS, "go").map((d) => [d.name, d.exported]); assert.deepEqual(found, [ ["Entry", true], @@ -107,42 +119,51 @@ test("a Go line declares a package-level func, type, var or const at column zero ["Rows", true], ["List", true], ["limit", false], + ["depth", false], ["usage", false], ["Write", true], ["Table", true], ["A", true], ["B", true], ["Ready", true], + ["Sum", true], + ["Once", true], + ["β", false], + ["Γ", true], ["Version", true], ["Count", true], ["Arr", true], ["Map", true], + ["generated", false], + ["After", true], ["main", false], ]); - for (const name of ["depth", "limit", "Reader", "B", "Map"]) assert.ok(goDeclaresAtTop(DECLARATIONS, name), `${name} is declared at the top level`); - for (const name of ["ID", "Name", "Read", "Hidden", "Commented", "_", "Method", "local", "inner", "store", "fmt"]) assert.ok(!goDeclaresAtTop(DECLARATIONS, name), `${name} is not`); + for (const name of ["depth", "limit", "Reader", "B", "Map", "β", "After"]) assert.ok(atTop(DECLARATIONS, name), `${name} is declared at the top level`); + for (const name of ["ID", "Name", "Read", "Hidden", "Commented", "Fake", "_", "Method", "local", "inner", "store", "fmt"]) assert.ok(!atTop(DECLARATIONS, name), `${name} is not`); }); -test("what a Go declaration line declares, alone or read by the scan just before: an interface or alias is a type only, a const a value, a var by what it is set to, a func, struct or other defined type a body", () => { - const lines = DECLARATIONS.split("\n"); - declarationsOf(DECLARATIONS, "go"); - const at = (start: string): string => lines.find((l) => l.startsWith(start))!; - const read = (start: string): [string, boolean] => [declares(at(start), "go"), isTypeDeclaration(at(start), "go")]; - assert.deepEqual(read("type Entry"), ["body", false], "a struct's methods are declared apart from it"); - assert.deepEqual(read("\tReader"), ["type", true]); - assert.deepEqual(read("\tRows"), ["type", true], "a grouped alias"); - assert.deepEqual(read("\tList"), ["body", false], "a generic defined type, its type parameters passed over"); - assert.deepEqual(read("\tlimit"), ["value", false]); - assert.deepEqual(read("\tWrite"), ["body", false], "a var set to a func literal"); - assert.deepEqual(read("\tTable"), ["unknown", false], "a composite literal may hold a func"); - assert.deepEqual(read("\tA ="), ["value", false]); - assert.deepEqual(read("var Ready"), ["unknown", false], "a var set later may hold a func"); - assert.deepEqual(read("type Count"), ["body", false]); - assert.deepEqual(read("func Map"), ["body", false]); +test("what a Go declaration declares, read in its file: an interface or alias is a type only, a const a value, a var by its first value, a func, struct or other defined type a body", () => { + const kinds = new Map(declarationsOf(DECLARATIONS, "go").map((d) => [d.name, d.declares])); + const read = (name: string): string | undefined => kinds.get(name); + assert.equal(read("Entry"), "body", "a struct's methods are declared apart from it"); + assert.equal(read("Reader"), "type", "a grouped interface"); + assert.equal(read("Rows"), "type", "a grouped alias"); + assert.equal(read("List"), "body", "a generic defined type, its type parameters passed over"); + assert.equal(read("limit"), "value"); + assert.equal(read("usage"), "value", "a raw string, whatever lines it spans"); + assert.equal(read("Write"), "body", "a var set to a func literal"); + assert.equal(read("Once"), "unknown", "a func literal called: the var holds what it returns"); + assert.equal(read("Table"), "unknown", "a composite literal may hold a func"); + assert.equal(read("Sum"), "value", "no operator yields a func"); + assert.equal(read("Γ"), "value", "each name of a list read by the list's first value"); + assert.equal(read("A"), "value"); + assert.equal(read("Ready"), "unknown", "a var set later may hold a func"); + assert.equal(read("Count"), "body"); + assert.equal(read("Map"), "body"); assert.equal(declares("func (e *Entry) Method() string { return e.ID }", "go"), "unknown", "a method is no package-level declaration"); }); -test("a Go import is read single and grouped, named, dot and blank, never from a comment or a string, and blanking keeps every offset", () => { +test("a Go import is read single and grouped, named, dot and blank, never from a comment or a string, each whole package narrowed to the exported names the file uses through the name it binds; blanking keeps every offset", () => { const text = [ "package api", "", @@ -154,17 +175,31 @@ test("a Go import is read single and grouped, named, dot and blank, never from a "\t. \"shop/dot\"", "\t`shop/raw`", "\t// \"shop/commented\"", + "\t\"gopkg.in/yaml.v3\"", ")", "", "var s = \"import \\\"shop/in_string\\\"\"", + "var src = `", + "package fake", + "import \"shop/in_raw\"", + "`", + "", + "func Handle(w http.ResponseWriter, rows ...st.Row) {", + "\tfmt.Println(st.Seal(rows), st.lower, yaml.Marshal, raw.X)", + "\tdot := 1", + "\t_ = dot.Field", + "}", ].join("\n"); - assert.deepEqual(importsIn(text).map((i) => `${i.alias ?? "-"} ${i.path}`), ["- fmt", "st shop/store", "- net/http", "_ shop/side", ". shop/dot", "- shop/raw"]); + const imports: string[] = []; + parsedOf("go", "source")!.importsOf(text, (name, specifier) => imports.push(`${name ?? "*"} <- ${specifier}`)); + assert.deepEqual(imports, ["Println <- fmt", "Row <- shop/store", "Seal <- shop/store", "ResponseWriter <- net/http", "* <- shop/side", "* <- shop/dot", "X <- shop/raw", "Marshal <- gopkg.in/yaml.v3"], "a variadic ...st.Row is a use; an unexported st.lower is none; a local named as a dot-imported package is no qualifier of it"); + assert.deepEqual(parsedOf("go", "interfaces")!.importLists(text), ["shop/store as st, shop/side as _, shop/dot as ."]); assert.equal(uncommented(text).length, text.length); assert.equal(codeOnly(text).length, text.length); assert.deepEqual(["shop/store", "gopkg.in/yaml.v3", "github.com/go-chi/chi/v5", "example.com/go-redis"].map(packageNameOf), ["store", "yaml", "chi", "redis"]); }); -test("a Go import path resolves under the module go.mod names, and the root's go.work, to the file of the package that declares each name the file uses through it; a package used for its side effects, dot-imported or never spelled is its first file; any other path resolves to nothing; a deleted file stands in for the names no file left declares", () => { +test("a Go import path resolves under the module go.mod names, and the root's go.work, to the package, each name the file uses through it joining the file that declares it; a package used for its side effects, dot-imported or never spelled joins every file of it; any other path resolves to nothing; a deleted file stays among its files, so a name no file left declares still finds its importer", () => { const root = project({ "go.mod": "module example.com/shop\n\ngo 1.22\n", "go.work": "go 1.22\n\nuse (\n\t.\n\t./tools\n)\n", @@ -193,19 +228,22 @@ test("a Go import path resolves under the module go.mod names, and the root's go "}", ].join("\n"); const imports = (file: string, text: string, vanished?: ReadonlySet): string[] => importsOf(root, file, text, "go", vanished).map((i) => `${i.name ?? "*"} <- ${i.module}`); - assert.deepEqual(imports("api/render.go", api), ["* <- store/a_rows.go", "* <- store/secrets.go", "* <- side/side.go", "* <- tools/lint/lint.go"], "each name from the file that declares it; a blank import whole; a module go.work uses; the standard library and another module nothing"); - assert.deepEqual(imports("api/render.go", "package api\n\nimport . \"example.com/shop/store\"\n\nvar x = Seal\n"), ["* <- store/a_rows.go"], "a dot import is of the package whole"); - assert.deepEqual(imports("api/render.go", "package api\n\nimport \"example.com/shop/store\"\n"), ["* <- store/a_rows.go"], "an import whose names the file never spells is of the package whole"); + assert.deepEqual(imports("api/render.go", api), ["Row <- store/a_rows.go", "Seal <- store/secrets.go", "SecretColumns <- store/secrets.go", "* <- side/side.go", "Run <- tools/lint/lint.go"], "each name from the file that declares it; a blank import whole; a module go.work uses; the standard library and another module nothing"); + assert.deepEqual(imports("api/render.go", "package api\n\nimport . \"example.com/shop/store\"\n\nvar x = Seal\n"), ["* <- store/a_rows.go", "* <- store/secrets.go"], "a dot import is of the package whole"); + assert.deepEqual(imports("api/render.go", "package api\n\nimport \"example.com/shop/store\"\n"), ["* <- store/a_rows.go", "* <- store/secrets.go"], "an import whose names the file never spells is of the package whole"); const gone = new Set(["store/b_cache.go"]); - assert.deepEqual(imports("api/render.go", "package api\n\nimport \"example.com/shop/store\"\n\nvar c = store.Cache\nvar s = store.Seal\n", gone), ["* <- store/b_cache.go", "* <- store/secrets.go"], "a name no file left declares resolves to the deleted file, so its importer is found"); + assert.deepEqual(imports("api/render.go", "package api\n\nimport \"example.com/shop/store\"\n\nvar c = store.Cache\nvar s = store.Seal\n", gone), ["Cache <- store/a_rows.go", "Cache <- store/b_cache.go", "Cache <- store/secrets.go", "Seal <- store/secrets.go"], "a name no file left declares joins every file of the package, the deleted one among them, so its importer is found"); }); -test("the Go interfaces slot: Go renames packages, never names, so no import list holds an alias; it has no default export; gopls takes no bounds; a dot import's names are spelled at each use", () => { - assert.deepEqual(GO_INTERFACES.importLists("import st \"shop/store\"\n"), []); - assert.deepEqual(GO_INTERFACES.defaultNames("package x\n"), []); - assert.deepEqual(GO_INTERFACES.wildcardModules("api/render.go", "import . \"shop/store\"\n"), []); - assert.equal(GO_INTERFACES.isDefaultExport("func Render() {}"), false); - assert.equal(GO_INTERFACES.serverBounds, false); +test("the Go interfaces reading: an interface or alias line is a type declaration, it has no default export, gopls takes no bounds, and a dot import keys no wildcard path, since its names are spelled at each use", () => { + const interfaces = parsedOf("go", "interfaces")!; + assert.equal(interfaces.isTypeDeclaration("type Reader interface{ Read() }"), true); + assert.equal(interfaces.isTypeDeclaration("type Rows = []Row"), true); + assert.equal(interfaces.isTypeDeclaration("type Row struct{}"), false); + assert.deepEqual(interfaces.defaultNames("package x\n"), []); + assert.deepEqual(interfaces.wildcardModules("api/render.go", "package api\n\nimport . \"shop/store\"\n"), []); + assert.equal(interfaces.isDefaultExport("func Render() {}"), false); + assert.equal(syntaxOf("go", "interfaces")?.serverBounds ?? false, false, "Go fills no interfaces table, so its server takes no bounds"); }); test("mass reads a Go project as it reads the other languages: its files counted, its declarations found, and no language named not read", () => { diff --git a/src/adapters/project-files.test.ts b/src/adapters/project-files.test.ts index 9f9d9483..d0cb4288 100644 --- a/src/adapters/project-files.test.ts +++ b/src/adapters/project-files.test.ts @@ -10,7 +10,7 @@ import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { after, before, test } from "node:test"; @@ -194,3 +194,32 @@ test("a folder the config names as a plugin is not the project's source: its fil rmSync(adopter, { recursive: true, force: true }); } }); + +test("a reading is handed only files it can open: a pipe, a link to a pipe, a link to a folder and a link to nothing are no project file, in a repository or out of one, and a change keeps every path it names but a folder, a pipe or a link to one", () => { + for (const versioned of [true, false]) { + const root = mkdtempSync(join(tmpdir(), "coherence-unreadable-")); + try { + writeFileSync(join(root, "own.py"), "OWN = 1\n"); + symlinkSync("own.py", join(root, "linked.py")); + spawnSync("mkfifo", [join(root, "pipe.py")]); + symlinkSync("pipe.py", join(root, "to-pipe.py")); + mkdirSync(join(root, "folder")); + writeFileSync(join(root, "folder", "inside.py"), "INSIDE = 1\n"); + symlinkSync("folder", join(root, "to-folder.py")); + symlinkSync("nowhere.py", join(root, "dangling.py")); + writeFileSync(join(root, "deleted.py"), "GONE = 1\n"); + if (versioned) { + spawnSync("git", ["init", "-q"], { cwd: root }); + spawnSync("git", ["add", "-A"], { cwd: root }); + spawnSync("git", ["-c", "user.name=t", "-c", "user.email=t@t", "-c", "commit.gpgsign=false", "commit", "-q", "-m", "start"], { cwd: root }); + } + rmSync(join(root, "deleted.py")); + assert.deepEqual(projectFiles(root), ["folder/inside.py", "linked.py", "own.py"], `${versioned ? "in a repository" : "out of one"}: a regular file, and a link to one, alone`); + // A change is every path it names but a folder, a pipe, a socket, a device or a link to a pipe, a socket or a device: a link relinked to a folder or left dangling changed, and a deleted file too. + const kept = [...keepProjectFiles(root, ["own.py", "folder", "pipe.py", "to-pipe.py", "to-folder.py", "dangling.py", "deleted.py"])].sort(); + assert.deepEqual(kept, ["dangling.py", "deleted.py", "own.py", "to-folder.py"], `${versioned ? "in a repository" : "out of one"}: a path an edit names is kept unless a read of it would wait or it is a folder, a deleted file among them`); + } finally { + rmSync(root, { recursive: true, force: true }); + } + } +}); diff --git a/src/adapters/project-files.ts b/src/adapters/project-files.ts index 828d72d4..3e7def76 100644 --- a/src/adapters/project-files.ts +++ b/src/adapters/project-files.ts @@ -78,17 +78,42 @@ function insideNested(root: string, rel: string, memo: Map): bo return false; } +/** + * Whether a listed path is a file a reading may open: a regular file, or a + * link to one. Never a folder, a pipe, a socket or a device, which a read + * waits on forever or reads without end, and never a link that leads to one + * of those or nowhere. The one test every enumeration of the project's files + * passes, so no reading is handed what it cannot read. + */ function isFileOnDisk(root: string, rel: string): boolean { try { - return !lstatSync(join(root, rel)).isDirectory(); + const entry = lstatSync(join(root, rel)); + return entry.isFile() || (entry.isSymbolicLink() && statSync(join(root, rel)).isFile()); } catch { return false; } } -function isFolderOnDisk(root: string, rel: string): boolean { +/** + * Whether what is at a path a change names is no file of the change: a + * folder, or a pipe, a socket or a device, which a read waits on forever or + * reads without end, or a link to one of those. A link git tracks is a file + * of the change whatever it leads to, a folder or nothing: relinked or left + * dangling, it changed. A path with nothing at it (a tracked file an edit + * deleted) is not. + */ +function isOtherOnDisk(root: string, rel: string): boolean { + let entry; + try { + entry = lstatSync(join(root, rel)); + } catch { + return false; + } + if (entry.isDirectory()) return true; + if (!entry.isSymbolicLink()) return !entry.isFile(); try { - return lstatSync(join(root, rel)).isDirectory(); + const target = statSync(join(root, rel)); + return !target.isFile() && !target.isDirectory(); } catch { return false; } @@ -385,7 +410,7 @@ export function keepProjectFiles(root: string, paths: readonly string[], listing const memo = new Map(); const plugins = pluginFolders(base); const candidates = [...new Set(paths.map((p) => projectRelative(base, p)).filter((rel): rel is string => rel !== undefined))].filter( - (rel) => !insideNested(base, rel, memo) && !inPluginFolder(rel, plugins) && !isFolderOnDisk(base, rel) && !rel.split("/").includes(".git"), + (rel) => !insideNested(base, rel, memo) && !inPluginFolder(rel, plugins) && !isOtherOnDisk(base, rel) && !rel.split("/").includes(".git"), ); if (candidates.length === 0 || !inRepository(base)) { return new Set(inRepository(base) ? [] : candidates.filter((rel) => !rel.split("/").includes("node_modules"))); diff --git a/src/adapters/rust-source.test.ts b/src/adapters/rust-source.test.ts index b3ee6ef8..46930f09 100644 --- a/src/adapters/rust-source.test.ts +++ b/src/adapters/rust-source.test.ts @@ -1,8 +1,9 @@ /** * The Rust plugin's text scans (plugins/rust/rust-source.ts, rust-scope.ts, - * rust-interfaces.ts): what a line declares, what a use tree brings in, where - * a module path resolves by Cargo's layout and the workspace's manifests, - * and that mass reads Rust as it reads the other languages. + * rust-interfaces.ts, rust-lists.ts): what a line declares, what a use tree + * brings in, where a module path resolves by Cargo's layout and the + * workspace's manifests, what a hand-kept list holds, and that mass reads + * Rust as it reads the other languages. */ import assert from "node:assert/strict"; @@ -14,7 +15,8 @@ import { computeMass, formatMass } from "../economy/mass.ts"; import { declarationsOf, importsOf } from "../economy/source.ts"; import { declares } from "../observation/interfaces.ts"; import { isTypeDeclaration } from "../readings/scope/component-interfaces.ts"; -import { RUST_INTERFACES } from "../../plugins/rust/rust-scope.ts"; +import { parsedOf } from "../plugins/languages.ts"; +import { rustListOf } from "../../plugins/rust/rust-lists.ts"; import { uncommented, useLeaves } from "../../plugins/rust/rust-source.ts"; const madeFolders: string[] = []; @@ -32,7 +34,7 @@ function project(files: Record): string { return root; } -test("a Rust line declares an item at column zero under any visibility and qualifier, exported when pub in any form; an impl, a use or an indented item declares nothing", () => { +test("a Rust file declares each item at its top level under any visibility and qualifier, exported when pub in any form, named as written; an impl, a use, an item inside another or in a string declares nothing", () => { const text = [ "pub const SECRET: &str = \"t\";", "pub(crate) async fn seal() {}", @@ -49,17 +51,22 @@ test("a Rust line declares an item at column zero under any visibility and quali "use crate::store::Row;", "extern crate alloc;", "fn r#match() {}", + "#[derive(Debug)] pub struct Tagged;", + "const DOC: &str = \"", + "fn in_string() {}", + "\";", ].join("\n"); assert.deepEqual( declarationsOf(text, "rust").map((d) => [d.name, d.exported]), - [["SECRET", true], ["seal", true], ["Row", true], ["raw", false], ["COUNT", false], ["Sealer", true], ["Rows", false], ["tests", false], ["row", false], ["match", false]], + [["SECRET", true], ["seal", true], ["Row", true], ["raw", false], ["COUNT", false], ["Sealer", true], ["Rows", false], ["tests", false], ["row", false], ["r#match", false], ["Tagged", true], ["DOC", false]], + "a raw identifier is named as rust-analyzer names it, r# kept; an item after an attribute on its line is read", ); const lines = text.split("\n"); assert.deepEqual(lines.slice(0, 9).map((l) => declares(l, "rust")), ["value", "body", "body", "body", "value", "type", "type", "unknown", "body"]); - assert.deepEqual(lines.slice(0, 9).map((l) => isTypeDeclaration(l, "rust")), [false, false, false, false, false, false, true, false, false], "a type alias alone declares a type only"); + assert.deepEqual(lines.slice(0, 9).map((l) => isTypeDeclaration(l, "rust")), [false, false, false, false, false, true, true, false, false], "a trait and a type alias declare a type, as declares says"); }); -test("a use tree is read leaf by leaf through nested braces, renames, self and globs, and nothing in a comment or a string is read", () => { +test("a use tree is read leaf by leaf through nested braces, renames, self and globs, each path as an item of its module and as the module, and nothing in a comment or a string is read", () => { const text = [ "use crate::{store::{self, seal as close, Row}, api::*};", "pub(crate) use super::super::util::helper;", @@ -76,7 +83,39 @@ test("a use tree is read leaf by leaf through nested braces, renames, self and g ["crate::store::self", "crate::store::seal as close", "crate::store::Row", "crate::api::*", "super::super::util::helper", "::serde::Serialize", "crate::after::Seen"], ); assert.equal(uncommented(text).length, text.length, "blanking keeps every offset"); - assert.deepEqual(RUST_INTERFACES.importLists("use a::{b as c};"), ["a::{b as c}"], "the renames are read from the tree's text"); + // Through the parser: each leaf spelled whole, its group's paths before it. + const read: string[] = []; + parsedOf("rust", "source")!.importsOf(text, (name, specifier) => read.push(name === undefined ? specifier : `${name} from ${specifier}`)); + assert.deepEqual( + [...new Set(read)].sort(), + ["::serde::Serialize", "Row from crate::store", "Seen from crate::after", "Serialize from ::serde", "crate::after::Seen", "crate::api", "crate::store::Row", "crate::store::seal", "crate::store::self", "helper from super::super::util", "seal from crate::store", "super::super::util::helper"], + ); + const interfaces = parsedOf("rust", "interfaces")!; + assert.deepEqual(interfaces.importLists("use a::{b as c};"), ["b as c, a::b as c"], "a rename is read as the name and as the path it renames"); + assert.deepEqual(interfaces.wildcardModules("src/x.rs", text), ["src/api.rs", "src/api/mod.rs"], "a glob in a group is read under the group's path"); +}); + +test("a Rust list is the array a top-level const or static is set to: its string literals, a tuple by its first, a path by its last segment, through & and vec!; what it cannot read is kept as written, and a comment or a string's brackets are no member", () => { + const text = [ + 'pub const KINDS: &[&str] = &["box", /* ground */ "plane", r#"say "hi""#];', + "static TABLE: [(&str, u32); 2] = [", + ' ("a", 1), // the first', + ' ("b, ]", 2),', + "];", + "pub(crate) static SHAPES: &'static [Kind] = &[Kind::Box, shape::Kind::Sphere, 3, make(\"x\")];", + "const NAMES: Vec<&str> = vec![\"x\"];", + "const COUNT: usize = 3;", + "fn body() {", + ' const INNER: &[&str] = &["not top"];', + "}", + ].join("\n"); + assert.deepEqual(rustListOf(text, "KINDS"), { line: 1, kind: "array", members: ["box", "plane", 'say "hi"'], unread: [] }); + assert.deepEqual(rustListOf(text, "TABLE"), { line: 2, kind: "array", members: ["a", "b, ]"], unread: [] }, "past the type's [..; 2], a row by its first column, a comma and a bracket in a string kept in it"); + assert.deepEqual(rustListOf(text, "SHAPES"), { line: 6, kind: "array", members: ["Box", "Sphere"], unread: ["3", 'make("x")'] }); + assert.deepEqual(rustListOf(text, "NAMES")?.members, ["x"]); + assert.equal(rustListOf(text, "COUNT"), undefined, "a const set to no array is no list"); + assert.equal(rustListOf(text, "INNER"), undefined, "a const inside a fn is not at the top"); + assert.equal(rustListOf(text, "MISSING"), undefined); }); test("a Rust path resolves by its crate's folder layout: crate, self, super and a module of the file's own, a.rs or a/mod.rs, a crate of the workspace by its package name, a [[bin]] root's modules beside it, and only under the file's exact spelling", () => { @@ -93,13 +132,45 @@ test("a Rust path resolves by its crate's folder layout: crate, self, super and "tool/flags/mod.rs": "pub fn parse() {}\n", }); const imports = (file: string, text: string): string[] => importsOf(root, file, text, "rust").map((i) => `${i.name ?? "*"} <- ${i.module}`); - assert.deepEqual(imports("crates/shop/src/store/rows.rs", "use super::seal;\nuse super::super::api::render;\nuse crate::api;\n"), ["seal <- crates/shop/src/store/mod.rs", "render <- crates/shop/src/api.rs", "api <- crates/shop/src/lib.rs", "* <- crates/shop/src/api.rs"]); + assert.deepEqual(imports("crates/shop/src/store/rows.rs", "use super::seal;\nuse super::super::api::render;\nuse crate::api;\n").sort(), ["* <- crates/shop/src/api.rs", "api <- crates/shop/src/lib.rs", "render <- crates/shop/src/api.rs", "seal <- crates/shop/src/store/mod.rs"]); const api = imports("crates/shop/src/api.rs", "use crate::store::{seal, rows::*};\nuse store::seal as again;\nuse serde::Serialize;\nuse crate::HiArgs;\n"); assert.ok(api.includes("seal <- crates/shop/src/store/mod.rs") && api.includes("* <- crates/shop/src/store/rows.rs"), api.join("\n")); assert.ok(!api.some((line) => line.includes("serde")), "a path into a crate outside the workspace resolves to nothing"); assert.ok(!api.some((line) => line.includes("hiargs")), "HiArgs is an item of the crate root, never the module file hiargs.rs, on any disk"); - assert.deepEqual(imports("tool/main.rs", "mod flags;\nuse shop_core::store::seal;\nuse ::shop_core::api::render;\n"), ["seal <- crates/shop/src/store/mod.rs", "render <- crates/shop/src/api.rs", "* <- tool/flags/mod.rs"], "a workspace crate by its package name, - read as _; a [[bin]] root's module beside it"); - assert.deepEqual(RUST_INTERFACES.wildcardModules("crates/shop/src/api.rs", "use crate::store::rows::*;\n"), ["crates/shop/src/store/rows.rs", "crates/shop/src/store/rows/mod.rs"], "a glob names its module in both layouts"); + assert.deepEqual(imports("tool/main.rs", "mod flags;\nuse shop_core::store::seal;\nuse ::shop_core::api::render;\n").sort(), ["* <- tool/flags/mod.rs", "render <- crates/shop/src/api.rs", "seal <- crates/shop/src/store/mod.rs"], "a workspace crate by its package name, - read as _; a [[bin]] root's module beside it"); + assert.deepEqual(parsedOf("rust", "interfaces")!.wildcardModules("crates/shop/src/api.rs", "use crate::store::rows::*;\n"), ["crates/shop/src/store/rows.rs", "crates/shop/src/store/rows/mod.rs"], "a glob names its module in both layouts"); +}); + +test("a use inside an inline module is read from that module: super leaves it before the file's own, a path still inside it leads to no other file, and a bare path there names a crate", () => { + const root = project({ + "Cargo.toml": '[package]\nname = "shop"\n', + "src/lib.rs": "pub mod store;\npub mod api;\n", + "src/store/mod.rs": "pub fn seal() {}\npub mod rows;\n", + "src/store/rows.rs": "pub struct Row;\n", + "src/api.rs": "", + }); + const text = [ + "pub fn render() {}", + "#[cfg(test)]", + "mod tests {", + " use super::*;", + " use super::super::store::seal;", + " use crate::store::rows::Row;", + " use shop::store::rows;", + " use self::helpers::Fixture;", + " use store::Shadow;", + " mod deeper {", + " use super::super::render;", + " use super::super::super::store::*;", + " }", + "}", + ].join("\n"); + assert.deepEqual( + importsOf(root, "src/api.rs", text, "rust").map((i) => `${i.name ?? "*"} <- ${i.module}`).sort(), + ["* <- src/store/mod.rs", "* <- src/store/rows.rs", "Row <- src/store/rows.rs", "rows <- src/store/mod.rs", "seal <- src/store/mod.rs"], + "use super::* in a test module is this file, never the crate root; super::super leaves the inline module, then the file's; a bare path inside it is a crate", + ); + assert.deepEqual(parsedOf("rust", "interfaces")!.wildcardModules("src/api.rs", text), ["src/store.rs", "src/store/mod.rs"], "a glob of the file's own module keys no file; one that leaves it keys the module it reaches"); }); test("mass reads a Rust project as it reads the other languages: its files counted, reach followed through its use trees and mod declarations, and no language named not read", () => { diff --git a/src/adapters/walks.test.ts b/src/adapters/walks.test.ts index b247bab2..d492f839 100644 --- a/src/adapters/walks.test.ts +++ b/src/adapters/walks.test.ts @@ -4,8 +4,9 @@ * folders a name list once skipped (api/public, dist, build, public) beside * the folders a rule does leave out: the config's ignore list, a hidden * folder, a host's folder, a dependency install, an interpreter's cache and - * a virtual environment, and Cargo's build folder (a target beside a - * Cargo.toml; a folder named target elsewhere is code). Every walker must read exactly what the one rule + * a virtual environment, Cargo's build folder (a target beside a + * Cargo.toml; a folder named target elsewhere is code) and wasm-pack's + * output (a pkg beside a Cargo.toml; a pkg elsewhere is code). Every walker must read exactly what the one rule * leaves in, narrowed only by kind, and the rule must account for every * project file it leaves out. */ @@ -29,7 +30,7 @@ import { detectedEntrances } from "../readings/scope/component-interfaces.ts"; const IGNORE = ["vendor"]; /** Code a folder-name list once skipped: every walk must read it. */ -const NAMED_FOLDER_CODE = ["api/public/urls.py", "api/public/views.py", "dist/tool.py", "build/steps.py", "public/page.ts", "target/plan.py"]; +const NAMED_FOLDER_CODE = ["api/public/urls.py", "api/public/views.py", "dist/tool.py", "build/steps.py", "public/page.ts", "target/plan.py", "pkg/plan.py"]; /** Files a rule leaves out, with the rule that must name it. */ const LEFT_OUT: Record = { @@ -40,6 +41,7 @@ const LEFT_OUT: Record = { "pkg/__pycache__/cached.py": "environment folder: pkg/__pycache__", "env/lib/site.py": "virtual environment: env", "crate/target/debug/generated.py": "Cargo build folder: crate/target", + "crate/pkg/crate.ts": "wasm-pack output: crate/pkg", }; let root: string; @@ -60,6 +62,7 @@ before(() => { write("build/steps.py", "def steps():\n return None\n"); write("public/page.ts", "export const page = 1;\n"); write("target/plan.py", "def plan():\n return None\n"); + write("pkg/plan.py", "def plan():\n return None\n"); write("crate/Cargo.toml", '[package]\nname = "crate"\nversion = "0.1.0"\n'); write("env/pyvenv.cfg", "home = /usr/bin\n"); for (const file of Object.keys(LEFT_OUT)) write(file, file.endsWith(".ts") ? "export const x = 1;\n" : "def x():\n return None\n"); diff --git a/src/build.ts b/src/build.ts index 887a00d8..6314bfa9 100644 --- a/src/build.ts +++ b/src/build.ts @@ -69,7 +69,7 @@ for (const file of files(plugins)) { const text = readFileSync(file, "utf8"); // Every module a manifest names (its module and each syntax slot's) by the .js the build wrote. writeFileSync((mkdirSync(dirname(join(bundled, at)), { recursive: true }), join(bundled, at)), basename(file) === "plugin.json" ? text.replace(/("[A-Za-z]+":\s*"[^"#/]+)\.ts(["#])/g, "$1.js$2") : text); - } + } else if (/\.(wasm|scm)$/.test(file)) copy(file, join(bundled, at)); // A plugin's parser and its queries (its manifest's treeSitter), as they are. } // The same modules the page joins, found the same way: from the entry, by what each imports at run time. diff --git a/src/bundled.e2e.ts b/src/bundled.e2e.ts index 1b5b2902..5761a2a9 100644 --- a/src/bundled.e2e.ts +++ b/src/bundled.e2e.ts @@ -60,6 +60,9 @@ function installedProject(name: string): { project: string; installed: string } run(unpacked, "tar", ["-xzf", tarball]); mkdirSync(join(project, "node_modules", "@posthog"), { recursive: true }); renameSync(join(unpacked, "package"), join(project, "node_modules", "@posthog", "coherence")); + // The package's dependencies beside it, as npm installs them: copied from this checkout's, so the test needs no registry. + const { dependencies = {} } = JSON.parse(readFileSync(join(CHECKOUT, "package.json"), "utf8")) as { dependencies?: Record }; + for (const dependency of Object.keys(dependencies)) cpSync(join(CHECKOUT, "node_modules", dependency), join(project, "node_modules", dependency), { recursive: true }); return { project, installed: join(project, "node_modules", "@posthog", "coherence") }; } @@ -74,21 +77,24 @@ test("the bundled plugins load from an installed package: every adapter module a const bundled = join(installed, "dist", "bundled"); const defaults = JSON.parse(readFileSync(join(bundled, "defaults.json"), "utf8")) as { plugins: string[] }; for (const name of defaults.plugins) { - const manifest = JSON.parse(readFileSync(join(bundled, name, "plugin.json"), "utf8")) as { module?: string; syntax?: Record }; - for (const named of [manifest.module, ...Object.values(manifest.syntax ?? {}).map((at) => at.split("#")[0])]) { + const manifest = JSON.parse(readFileSync(join(bundled, name, "plugin.json"), "utf8")) as { module?: string; syntax?: Record; treeSitter?: { parser: string; queries: string; resolve: string } }; + for (const named of [manifest.module, ...[...Object.values(manifest.syntax ?? {}), manifest.treeSitter?.resolve].map((at) => at?.split("#")[0])]) { if (named === undefined) continue; assert.match(named, /\.js$/, `${name} names ${named} as JavaScript`); assert.ok(existsSync(join(bundled, name, named)), `${name}'s ${named} is in the package`); } + for (const named of manifest.treeSitter === undefined ? [] : [manifest.treeSitter.parser, manifest.treeSitter.queries]) assert.ok(existsSync(join(bundled, name, named)), `${name}'s ${named} is in the package`); } // Loaded from node_modules: each language's slots and adapter, and the declared plugin's adapter. const probe = ` const languages = await import("@posthog/coherence/dist/plugins/languages.js"); - const out = { languages: [...languages.LANGUAGES], files: {}, slots: {}, adapters: {} }; + await (await import("@posthog/coherence/dist/plugins/syntax-trees.js")).startParsers(); + const out = { languages: [...languages.LANGUAGES], files: {}, slots: {}, parsed: {}, adapters: {} }; for (const file of ["a.ts", "b.py", "c.rs"]) out.files[file] = languages.languageOfFile(file) ?? null; for (const language of languages.LANGUAGES) { - out.slots[language] = ["entrances", "interfaces", "source", "declares", "notice"].filter((slot) => languages.syntaxOf(language, slot) !== undefined); + out.slots[language] = ["entrances", "interfaces", "notice"].filter((slot) => languages.syntaxOf(language, slot) !== undefined); + out.parsed[language] = ["source", "declares", "topLevel"].filter((reading) => languages.parsedOf(language, reading) !== undefined); out.adapters[language] = languages.coreAdapter(language, process.cwd()).constructor.name; } out.adapters.declared = languages.declaredAdapter({ name: "swift", extensions: [".swift"], server: ["sourcekit-lsp"] }, process.cwd()).constructor.name; @@ -98,15 +104,19 @@ test("the bundled plugins load from an installed package: every adapter module a languages: string[]; files: Record; slots: Record; + parsed: Record; adapters: Record; }; assert.deepEqual(said.languages, ["typescript", "python", "rust"]); assert.deepEqual(said.files, { "a.ts": "typescript", "b.py": "python", "c.rs": "rust" }); assert.deepEqual(said.slots, { - typescript: ["entrances", "interfaces", "source", "declares", "notice"], - python: ["entrances", "interfaces", "source", "declares"], - rust: ["entrances", "interfaces", "source", "declares"], + typescript: ["entrances", "interfaces", "notice"], + python: ["entrances", "interfaces"], + rust: ["entrances", "interfaces"], }); + // Each language's text read through its parser, as JavaScript too. + const everyReading = ["source", "declares", "topLevel"]; + assert.deepEqual(said.parsed, { typescript: everyReading, python: everyReading, rust: everyReading }); assert.deepEqual(said.adapters, { typescript: "TypeScriptAdapter", python: "PythonAdapter", rust: "RustAdapter", declared: "DeclaredAdapter" }); // The package's own command, reading the project's TypeScript through the bundled plugin's entrance rules: a package script it runs is detected. @@ -135,7 +145,7 @@ test("an ejected plugin, swapped in from an installed package, passes plugin che return { verdict: String(entry["verdict"]), grade: String(entry["grade"]), refutation: String(entry["refutation"]), bypasses: ((entry["bypasses"] ?? []) as { file: string; line: number }[]).map((b) => `${b.file}:${b.line}`), plugins: entry["plugins"] }; }; const before = graded("bundled"); - assert.deepEqual({ ...before, plugins: undefined }, { verdict: "fail", grade: "broken", refutation: "automatic", bypasses: ["src/api/render.ts:1", "src/api/render.ts:5"], plugins: undefined }); + assert.deepEqual({ ...before, plugins: undefined }, { verdict: "fail", grade: "broken", refutation: "automatic", bypasses: ["src/api/render.ts:1", "src/api/render.ts:6"], plugins: undefined }); assert.match(coherence("plugin", "eject", "typescript"), /^ejected plugin typescript into \.\/coherence-plugins\/typescript/m); assert.match(coherence("plugin", "check", "./coherence-plugins/typescript"), /^plugin check typescript \(\.\/coherence-plugins\/typescript, typescript, [^)]*\): pass$/m, "the copy, reading Coherence through @posthog/coherence/plugin, owes what the bundled one does"); const after = graded("ejected"); diff --git a/src/cli.ts b/src/cli.ts index 576d0717..483c64cb 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -73,6 +73,12 @@ import { CI_USAGE, ciInstallCommand, ciSuggestion } from "./lifecycle/ci.ts"; import { ciReportCommand } from "./lifecycle/ci-report.ts"; import { startTelemetry } from "./lifecycle/telemetry.ts"; import { reachNote, refreshLatest, startUpdateCheck, versionText } from "./lifecycle/version.ts"; +import { startParsers } from "./plugins/syntax-trees.ts"; +import { warmProjectParses } from "./economy/warm-parses.ts"; +import { shapeCensus, shapesText } from "./plugins/shapes.ts"; +import { calibrate, calibrationText } from "./plugins/calibrate.ts"; +import { compareReference, compareText } from "./plugins/check.ts"; +import { readEnforcementConfig } from "./enforcement/config.ts"; type CommandResult = number | Promise; type RootCommand = (argv: string[], io: Io) => CommandResult; @@ -90,6 +96,9 @@ ${ECONOMY_USAGE} ${QUERY_USAGE} ${SCOPE_USAGE} coherence plugin eject [--to ] copy a bundled plugin's source and its check.json into the project (coherence-plugins/ by default) and point the config's plugins at the copy, which then answers in the bundled plugin's place + coherence plugin compare every language plugin's reading of the reference project side by side (the bundled ones and the project's), each relation one row, each plugin that reads one another way named; exit 1 when any does + coherence plugin calibrate [--files ] hold each language's text reading to its language server over the project's first n source files (200): the declarations the server reports too, those it does not (misreads), and what the server reports that the reading leaves out, by kind + coherence plugin shapes count each shape of import the project's code takes (named, renamed, glob, whole module, spans lines, inside a block), through its languages' parsers, beside the plugin's check projects; a shape the project writes and no check project holds is named untested coherence plugin check hold a plugin, bundled by name or a folder, to what every language plugin owes (file rule, declarations, references, a chokepoint graded) over its check.json's project; pass or fail per duty, exit 1 unless all pass coherence adopt list the folder in the registry (projects in coherence.config.json at the repository top), creating it when absent coherence hook <${HOOK_EVENTS.join("|")}> @@ -314,9 +323,27 @@ const HOOKS_FLAGS: Record> = { /** plugin eject [--to ] | plugin check : the eject, enhance and swap workflow (docs/plugins.md). */ async function pluginCommand(call: CommandCall, args: string[], root: string): Promise { - const { flags, positionals } = parse(args, new Set(["to"])); + const { flags, positionals } = parse(args, new Set(["to", "files"])); const [verb, given, ...more] = positionals; - if (given === undefined || more.length > 0 || (verb !== "eject" && verb !== "check")) fail(`plugin: eject [--to ], or check \n${USAGE}`); + if (verb === "compare") { + if (given !== undefined || flags.size > 0) fail(`plugin compare: no arguments; it reads every language plugin's check project\n${USAGE}`); + const readings = await compareReference(readEnforcementConfig(root).plugins); + call.stdout.write(`${compareText(readings)}\n`); + return readings.some((r) => !("held" in r) || r.missed.length > 0) ? 1 : 0; + } + if (verb === "calibrate") { + const files = flags.get("files"); + const limit = files === undefined ? 200 : Number(files); + if (given !== undefined || files === true || !Number.isInteger(limit) || limit < 1 || [...flags.keys()].some((f) => f !== "files")) fail(`plugin calibrate: [--files ]; it reads the project it runs in\n${USAGE}`); + call.stdout.write(`${calibrationText(await calibrate(root, limit))}\n`); + return 0; + } + if (verb === "shapes") { + if (given !== undefined || flags.size > 0) fail(`plugin shapes: no arguments; it reads the project it runs in\n${USAGE}`); + call.stdout.write(`${shapesText(await shapeCensus(root))}\n`); + return 0; + } + if (given === undefined || more.length > 0 || (verb !== "eject" && verb !== "check")) fail(`plugin: eject [--to ], check , or shapes\n${USAGE}`); if (verb === "check" && flags.size > 0) fail(`plugin check: no flags\n${USAGE}`); const to = flags.get("to"); if (to === true) fail(`plugin eject: --to names a folder\n${USAGE}`); @@ -526,6 +553,8 @@ export async function main(argv: string[], call: CommandCall): Promise { // A command that made Coherence's folder (a first run, a first journal record, without hooks install) writes its git files with it, // so git never offers the regenerated state for a commit; a folder that was already there keeps whatever its adopter left. const fresh = !existsSync(join(root, STATE_DIR)); + // The parser runtime starts before any command, so a reading of a language read through a parser finds it started (syntax-trees.ts). + await startParsers(); try { return await dispatch(argv, call, root); } finally { @@ -564,10 +593,18 @@ async function dispatch(argv: string[], call: CommandCall, root: string): Promis return runCommand(rest, io); case "refute": return refuteCommand(rest, io); - case "warm": - // Internal: the hook starts this detached so the instrument is loaded before the stop that needs it. - await warmInstrument(root); + case "warm": { + // Internal: the hook starts this detached so the instrument is loaded before the stop that needs it, + // and so every file the project reads through a parser is parsed once and kept before a whole-project reading asks. + const instrument = warmInstrument(root); + try { + warmProjectParses(root); + } catch { + // A pre-read that fails only means the first whole-project reading parses every file itself. + } + await instrument; return 0; + } case "serve": // The warm server answers the live Scope reading over HTTP besides the instrument over its socket. return serveCommand(rest, io, { http: scopeApp() }); diff --git a/src/economy/Economy.spec.md b/src/economy/Economy.spec.md index a38686f7..2d006c31 100644 --- a/src/economy/Economy.spec.md +++ b/src/economy/Economy.spec.md @@ -79,3 +79,9 @@ The context closure of a change, the read traces that record what sessions actua because: mass over a language it could not read printed "0% of lines" unreached at its head, which reads as every line reached, with the language named as not read only at the bottom (the blind Swift plugin session, 2026-10-22) refuted: made mass head with the unreached share even when it read no file, as before (mass.ts) -> "mass over a project whose only language no scan reads says it measured nothing, never 0% unreached" went red in economy.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-23) kinds: none +- an import of a module joins the files that declare what it imports: An import whose specifier a plugin resolves to a module (its folder and every file of it: a Go package, a SwiftPM target) joins, of the module's files, those that declare the name it imports; it joins every file of the module when it imports the module whole or no file of it declares the name. No plugin picks a file of a module. + over: a plugin by path whose resolve names a module of three files, imported by name, by a name no file declares, and whole; and the Go plugin's packages, by name, whole, dot-imported and with a file the change deleted + via: an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name + because: four plugins picked one file of a module four ways, and every one missed a file the importer used: the blind Swift plugins reached Row.swift or Secrets.swift for an import of Store whose names live in both (d-cb7829df, c-38a1baae) + refuted: made an import of a module join the module's first file alone, as Go's and two blind Swift plugins' rules did (src/economy/source.ts importsOf) -> "an import that resolves to a module joins, of its files, those that declare the name it imports, and every one when it imports the module whole or no file declares the name" went red in syntax-trees.test.ts on its own assertion (a name joins the file that declares it, and no other); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none diff --git a/src/economy/economy.test.ts b/src/economy/economy.test.ts index a85abe96..bd970e63 100644 --- a/src/economy/economy.test.ts +++ b/src/economy/economy.test.ts @@ -355,11 +355,10 @@ test("mass over a project whose only language no scan reads says it measured not writeFileSync(join(dir, path), text, "utf8"); }; try { - // A plugin that provides a language and fills no source slot: no bundled language is left unread (d-6569dec0), so the fixture brings its own. + // A plugin that provides a language and names no parser to read it through: no bundled language is left unread (d-6569dec0), so the fixture brings its own. put("coherence.config.json", JSON.stringify({ language: ["zz"], plugins: { zz: "./plugins/zz" } })); - put("plugins/zz/plugin.json", JSON.stringify({ name: "zz", version: "0.1.0", pluginApi: 2, provides: { language: "zz" }, module: "./index.ts", extensions: [".zz"], syntax: { topLevel: "top.ts#zzDeclaresAtTop" } })); + put("plugins/zz/plugin.json", JSON.stringify({ name: "zz", version: "0.1.0", pluginApi: 2, provides: { language: "zz" }, module: "./index.ts", extensions: [".zz"] })); put("plugins/zz/index.ts", 'export default { adapter: ({ language }) => ({ language, ladder: { top: "reference-choked", because: "a stand-in", rungs: [] }, ready: async () => ({ ok: true }), resolve: async () => ({ ok: false, reason: "a stand-in" }), references: async () => [], visibility: async () => ({ enforced: false, visible: true, evidence: "a stand-in" }), testFilter: (via) => via, refute: async () => ({ seen: false, staged: [], account: "a stand-in" }), forget: async () => {}, close: async () => {} }) };\n'); - put("plugins/zz/top.ts", "export const zzDeclaresAtTop = (text, name) => text.split(\"\\n\").includes(`verb ${name}`);\n"); put("src/Accounts.spec.md", "# Accounts\n\nThe accounts.\n"); put("src/post.zz", "verb post\n"); const printed = formatMass(computeMass(dir)); diff --git a/src/economy/source.ts b/src/economy/source.ts index 75189fd7..02aef265 100644 --- a/src/economy/source.ts +++ b/src/economy/source.ts @@ -1,17 +1,21 @@ /** * What economy and mass read from the tree without an instrument: which * files are source, which top-level names a file declares, which names it - * imports and from where, and which component a file lies in. A plain scan, - * never a parse; the adapter confirms what matters through resolve and - * references, and mass says when a number came from the scan alone. + * imports and from where, and which component a file lies in. A language is + * read through the parser its plugin names (syntax-trees.ts), and one whose + * plugin names none is not read. Neither asks a server: the adapter confirms + * what matters through resolve and references, and mass says when a number + * came from the scan alone. */ +import { readFileSync, statSync } from "node:fs"; import { isAbsolute, relative, resolve, sep } from "node:path"; import { isTestPath } from "../adapters/adapter.ts"; import { walkBounds, walkedProjectFiles } from "../adapters/project-files.ts"; import type { Language } from "../adapters/index.ts"; import { languageOfFile } from "../adapters/language-files.ts"; -import { leftOutOfSource, syntaxOf } from "../plugins/languages.ts"; +import { leftOutOfSource, parsedOf, treeReaderFor } from "../plugins/languages.ts"; +import type { Declares } from "../plugins/syntax-trees.ts"; import type { Component, SpecModel } from "../spec/model.ts"; /** @@ -43,47 +47,39 @@ export function toRelative(root: string, path: string): string | undefined { } /** - * What the plain scan reads of one language's source, each language's in its - * plugin's module (the `source` slot of its manifest's syntax): a language - * whose plugin fills no such slot declares nothing, imports nothing and - * resolves no specifier here, never reads as another language. + * What the scan reads of one language's source, derived from one parse + * through its plugin's parser (languages.ts parsedOf): a language whose + * plugin names no parser declares nothing, imports nothing and resolves no + * specifier here, never reads as another language. */ export interface SourceSyntax { - /** The name a line declares at the top level and whether its file exports it, or undefined when it declares none. */ - declarationOf(line: string): { name: string; exported: boolean } | undefined; - /** resolveModule for the language. */ - resolveModule(root: string, from: string, specifier: string, vanished: ReadonlySet): string | undefined; + /** resolveModule for the language: the file a specifier names, or the module of several files it names (a Go package, a SwiftPM target). */ + resolveModule(root: string, from: string, specifier: string, vanished: ReadonlySet): ImportTarget | undefined; /** Hands `add` each name the text imports with the specifier it comes from: undefined for a whole-module import. */ importsOf(text: string, add: (name: string | undefined, specifier: string) => void): void; } -/** The language's source scan, from its plugin; one that reads nothing for a language whose plugin fills no source slot. */ +/** The language's source scan, through its plugin's parser; one that reads nothing for a language whose plugin names none. */ function sourceSyntax(language: Language): SourceSyntax { - return syntaxOf(language, "source") ?? NO_SOURCE; + return parsedOf(language, "source") ?? NO_SOURCE; } -const NO_SOURCE: SourceSyntax = { declarationOf: () => undefined, resolveModule: () => undefined, importsOf: () => {} }; +const NO_SOURCE: SourceSyntax = { resolveModule: () => undefined, importsOf: () => {} }; export interface Declaration { name: string; /** One-based. */ line: number; exported: boolean; + /** What it declares, when the language is read through a parser, which says it in the same parse. */ + declares?: Declares; + /** Whether it is its module's default export, when the language is read through a parser, which says it in the same parse. */ + isDefault?: boolean; } -/** The top-level names a file declares, by a plain scan of line starts. */ +/** The top-level names a file declares, through the language's parser; none when its plugin names no parser. */ export function declarationsOf(text: string, language: Language): Declaration[] { - const found: Declaration[] = []; - const seen = new Set(); - const syntax = sourceSyntax(language); - text.split("\n").forEach((raw, index) => { - const line = raw.replace(/\r$/, ""); - const declared = syntax.declarationOf(line); - if (declared === undefined || seen.has(declared.name)) return; - seen.add(declared.name); - found.push({ name: declared.name, line: index + 1, exported: declared.exported }); - }); - return found; + return treeReaderFor(language)?.declarations(text) ?? []; } export interface Import { @@ -93,25 +89,64 @@ export interface Import { module: string; } +/** + * Where a specifier leads: one project-relative file, or a module of several + * (a Go package, a SwiftPM target), its folder and every file of it, project- + * relative. A plugin says which; which of a module's files an import reaches + * is the core's to say, the same for every language (importsOf). + */ +export type ImportTarget = string | { module: string; files: string[] }; + const NONE: ReadonlySet = new Set(); /** - * Resolve a module specifier from a file to a project-relative source file, + * Resolve a module specifier from a file to what it names under the root, * or undefined for a package or a file not under the root. A path in * `vanished` (a file the working change deleted or renamed away) resolves as * though it were still on disk, so its importers can be found. */ -export function resolveModule(root: string, from: string, specifier: string, language: Language, vanished: ReadonlySet = NONE): string | undefined { +export function resolveModule(root: string, from: string, specifier: string, language: Language, vanished: ReadonlySet = NONE): ImportTarget | undefined { return sourceSyntax(language).resolveModule(root, from, specifier, vanished); } -/** The names a file imports from files under the root, with the module each comes from; `vanished` as for resolveModule. */ +/** The names a module file declares at its top level, read once per file and again when it changes; none for a file gone from disk. */ +const DECLARED = new Map }>(); +function declaredIn(root: string, file: string, language: Language): Set { + const path = resolve(root, file); + let stamp: string; + try { + const stat = statSync(path, { bigint: true }); + stamp = `${stat.mtimeNs} ${stat.ctimeNs} ${stat.size}`; + } catch { + return new Set(); + } + const known = DECLARED.get(path); + if (known !== undefined && known.stamp === stamp) return known.names; + const names = new Set(declarationsOf(readFileSync(path, "utf8"), language).map((d) => d.name)); + DECLARED.set(path, { stamp, names }); + return names; +} + +/** + * The names a file imports from files under the root, with the file each comes + * from; `vanished` as for resolveModule. An import that resolves to a module + * reaches, of the module's files, those that declare the name it imports, and + * every one of them when it imports the module whole or no file of it + * declares the name: in a language whose module is several files, any of them + * can answer for the module, and no plugin picks one. + */ export function importsOf(root: string, file: string, text: string, language: Language, vanished: ReadonlySet = NONE): Import[] { const found: Import[] = []; const add = (name: string | undefined, specifier: string): void => { - const module = resolveModule(root, file, specifier, language, vanished); - if (module === undefined || module === file) return; - found.push({ name, module }); + const resolved = resolveModule(root, file, specifier, language, vanished); + if (resolved === undefined) return; + if (typeof resolved === "string") { + if (resolved !== file) found.push({ name, module: resolved }); + return; + } + const files = resolved.files.filter((f) => f !== file); + const declaring = name === undefined ? [] : files.filter((f) => declaredIn(root, f, language).has(name)); + for (const module of declaring.length > 0 ? declaring : files) found.push({ name, module }); }; sourceSyntax(language).importsOf(text, add); const seen = new Set(); diff --git a/src/economy/warm-parses.ts b/src/economy/warm-parses.ts new file mode 100644 index 00000000..1ff6b89b --- /dev/null +++ b/src/economy/warm-parses.ts @@ -0,0 +1,105 @@ +/** + * The parses a session start pre-reads: each language its project reads + * through a parser, every source file of it read once, so the project's kept + * parses (syntax-trees.ts) hold every file as it stands and a later reading + * of the whole project (mass, the economy's closure, the Structure reading) + * parses only what changed. Run by the warm-up the session start launches, + * detached, so no hook waits on it. + */ + +import { closeSync, constants, fstatSync, openSync, readFileSync, realpathSync } from "node:fs"; +import { resolve, sep } from "node:path"; +import { configIgnore } from "../adapters/project-files.ts"; +import { registryForLeaf } from "../adapters/project-config.ts"; +import { readEnforcementConfig } from "../enforcement/config.ts"; +import { forProject, sourceProvider } from "../plugins/languages.ts"; +import { warmParses } from "../plugins/syntax-trees.ts"; +import { sourceFiles } from "./source.ts"; + +/** + * Pre-read the project's files of every language it reads through a parser, + * and, when the project is a leaf of a registry, the repository top's too: + * the commands run there (mass, status) read every leaf and the top's own + * files, and the user's one store keeps them all. What each root and + * language read, and how many of those it parsed rather than found kept. + */ +export function warmProjectParses(rootGiven: string): { root: string; language: string; read: number; parsed: number }[] { + const root = resolve(rootGiven); + const top = registryForLeaf(root)?.top; + return [root, ...(top === undefined || resolve(top) === root ? [] : [resolve(top)])].flatMap((at) => warmRoot(at).map((w) => ({ root: at, ...w }))); +} + +function warmRoot(root: string): { language: string; read: number; parsed: number }[] { + const config = readEnforcementConfig(root); + const ignore = configIgnore(root); + return forProject(root, () => + config.languages.flatMap((language) => { + const plugin = sourceProvider(language); + if (plugin?.manifest.treeSitter === undefined) return []; + // In an order of this warm-up's own, so two warm-ups of one project at once (a session start and the prompt after it) mostly parse + // different files, each reading what the other has kept by then, where in one order they would parse every file twice. + const files = shuffled(sourceFiles(root, language, ignore)); + const within = realRoot(root); + const texts = (function* () { + for (const file of files) { + const text = warmText(resolve(root, file), within); + if (text !== undefined) yield text; + } + })(); + return [{ language, ...warmParses(plugin, root, texts) }]; + }), + ); +} + +/** The largest source file a warm-up reads: a generated file larger is read when a reading asks for it, never unasked. */ +const WARM_MAX_BYTES = 16 * 1024 * 1024; + +/** + * A source file's text as the warm-up reads it, unasked at a session start: + * only a regular file whose real path is inside the project, never through + * a link (one that leads out of the project, or to a pipe or a device), never blocking, and none larger than + * WARM_MAX_BYTES. Undefined for anything else, or a file gone since the walk + * listed it. + */ +function warmText(path: string, within: string): string | undefined { + // A file whose folder is a link out of the project (lib a link elsewhere, lib/x.py still listed) is no file of the project's. + try { + const real = realpathSync(path); + if (real !== within && !real.startsWith(within + sep)) return undefined; + } catch { + return undefined; + } + let fd: number; + try { + fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK); + } catch { + return undefined; + } + try { + const stat = fstatSync(fd); + return stat.isFile() && stat.size <= WARM_MAX_BYTES ? readFileSync(fd, "utf8") : undefined; + } catch { + return undefined; + } finally { + closeSync(fd); + } +} + +/** The same items in a random order (Fisher and Yates). */ +function shuffled(items: readonly T[]): T[] { + const out = [...items]; + for (let i = out.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [out[i], out[j]] = [out[j]!, out[i]!]; + } + return out; +} + +/** A project's root as the file system names it, every link followed. */ +function realRoot(root: string): string { + try { + return realpathSync(root); + } catch { + return root; + } +} diff --git a/src/enforcement/Enforcement.spec.md b/src/enforcement/Enforcement.spec.md index d56e05ab..e8280805 100644 --- a/src/enforcement/Enforcement.spec.md +++ b/src/enforcement/Enforcement.spec.md @@ -377,3 +377,6 @@ Enforcement by detection: the chokepoint check with its grade ladder and automat because: the server forwarded the protected thing and the chokepoint alone, so a served refutation of a check that exempts a folder never staged its use from outside the folder, and the occasion an adapter is told would never have reached it refuted: made the server's client send the protected thing and the chokepoint alone, as before, dropping the exempt folder and the occasion (server.ts) -> "a served refutation stages what the adapter in process stages, the exempt folder and the occasion carried" went red in server.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-23) kinds: none +- a via that maps to no test is said, never graded as a fail: When a run's batched pass finds no reported test whose title, or a group's title above it, is a bullet's via, while the same via run alone selects a test by pattern and passes, run --each names the via as naming no test exactly, with the titles it selected alone, instead of printing a fail batched beside a pass alone. + because: three bullets read 'no test ran' in every full batched run and passed alone, and run --each printed both verdicts without saying they disagreed, so the floor graded them failing while each targeted run passed (df-03839b92) + kinds: none diff --git a/src/enforcement/leak-guard.ts b/src/enforcement/leak-guard.ts index 54f193bf..482fc704 100644 --- a/src/enforcement/leak-guard.ts +++ b/src/enforcement/leak-guard.ts @@ -25,6 +25,14 @@ * test that made it; and every test is timed between hooks on the file's * root, and fails past its ceiling. * + * It also starts the parser runtime, as the CLI does before any command, so + * a test that asks a reading of a language read through a parser finds it + * started (syntax-trees.ts). + * + * It points XDG_CONFIG_HOME and XDG_CACHE_HOME at folders of the file's own, + * removed with it, so no test writes into the developer's Coherence folders, + * and no test reads parses another kept. + * * Inert in the runner's parent process (no NODE_TEST_CONTEXT), and in any * process a test spawns that does not itself load this module. */ @@ -33,6 +41,7 @@ import { execFileSync, watchSpawns } from "../lifecycle/work-meter.ts"; import { mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync, writeSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; +import { startParsers } from "../plugins/syntax-trees.ts"; import { declaredBudget, decisionHeld, describeSpawnBudget, describeTreeReads, launchesOwnCli, overCeiling, readsOwnTree, SPAWN_BUDGET, testCeiling, type Charged } from "./test-budgets.ts"; /** A process the guard found alive: its pid and its command line. */ @@ -149,6 +158,13 @@ function pause(ms: number): void { } async function install(): Promise { + // The user's Coherence folder (userConfigDir) is the file's own too, made beside its temp folder: a test that keeps parses + // never writes the parse store's key, or anything else, into the developer's real one. + const config = mkdtempSync(join(tmpdir(), "cg-config-")); + process.env["XDG_CONFIG_HOME"] = config; + // And the user's cache (userCacheDir), where kept parses live: each test file keeps its own, never the developer's. + const cache = mkdtempSync(join(tmpdir(), "cg-cache-")); + process.env["XDG_CACHE_HOME"] = cache; const folder = mkdtempSync(join(tmpdir(), "cg-")); process.env["TMPDIR"] = folder; process.env["COHERENCE_LEAK_GUARD"] = folder; @@ -173,6 +189,8 @@ async function install(): Promise { process.exitCode = 1; } rmSync(folder, { recursive: true, force: true }); + rmSync(config, { recursive: true, force: true }); + rmSync(cache, { recursive: true, force: true }); }); await installBudgets(file); } @@ -235,4 +253,7 @@ async function installBudgets(file: string): Promise { }); } -if (process.env["NODE_TEST_CONTEXT"] !== undefined) await install(); +if (process.env["NODE_TEST_CONTEXT"] !== undefined) { + await startParsers(); + await install(); +} diff --git a/src/journal/Journal.practice.md b/src/journal/Journal.practice.md index 2e99df56..1d4c26c6 100644 --- a/src/journal/Journal.practice.md +++ b/src/journal/Journal.practice.md @@ -1,21 +1,27 @@ -- close a defect: A defect is closed only when its whole class is guarded, or a decision says why fixing the instance suffices, and the guard has been seen to fire. - when: command coherence defect | command cli.* defect | command classify | command resolved df-* +- close a defect: A defect is closed only when a guard, an invariant seen to fire, covers its whole class (best after a fix that leaves the code no way to express it), or when a decision says why fixing the instance suffices or bounds a bug only time or a scheduler can show. + when: command coherence defect | command cli.* defect | command classify | command resolved df-* | explicit step: classify it: record the defect with --class, --introduced and --caught, or classify one already recorded (classify ); a class declared nowhere is declared once first, as the property class of defect (lexicon propose define defect) leaves: the defect's or the classification's id - step: sweep the codebase for siblings of the same shape (the same comparison, call or pattern wherever else it is written) and fix each one, then record the sweep: what was searched and every sibling it found, or that it found none - leaves: the sweep: what was searched and each sibling found and fixed, or none - step: guard or decide: name an invariant whose enforcement covers the whole class (a chokepoint, or a totality oracle over the class whose test fails on any member), adding the bullet when none exists; or record a decision saying why fixing the instance suffices + step: name what let the bug be written (the state a value can hold that it never should, or a second way to do what one function should do alone), then sweep the codebase for every sibling of that shape and record the sweep: what was searched and each sibling found, or that it found none + leaves: the representable shape, and the sweep + step: fix it so the code cannot express it again, in preference to a check at the site: one door every caller must pass (a function or class its module keeps private, so the compiler, or a totality oracle where the language has no such check, refuses any other caller), a type that cannot hold the bad value, a walk with a stack of its own rather than recursion over what input controls, a fact derived where it is needed rather than kept twice; route every sibling the sweep found through it. When the dead-end reading names the defect's component (DEAD END in spec --check, Dead ends in orient), weigh a different design for that component before adding any such door to the one it has, and record the choice, redesign or keep, as a decision + leaves: the door, type or derivation, and the siblings now routed through it; at a dead end, the decision choosing the design + step: guard or decide: name an invariant that fails on any second way to write the bug, a chokepoint the compiler grades or a totality oracle that reads the code and refuses each other door (another call, a name held under an alias, a module asked for by string), adding the bullet when none exists; or record a decision saying why fixing the instance suffices, or that only time or a scheduler can show the bug (a cost, a race), bounding it structurally all the same (a size every read passes, a lock only one process can take) leaves: the guard's / or the decision's id - step: refute the guard: witness a refutation of it, staging a break of the class's shape rather than replaying the instance + step: refute the guard: witness a refutation of it, staging a second way to write the bug rather than replaying the instance leaves: the refutation's run record step: record the close: resolved --because "" with --guard / or --decision , then run spec --check leaves: the resolution's id; spec --check names no close with neither pitfall: the symbolic-link spelling was fixed where the upgrade test found it, and only a sweep of the same comparison found the second site, in practice delivery's cd routing (df-ccfd4309, 4b1890f) pitfall: a second door opened past the warm server's chokepoint reached main because nothing that ran before the merge checked chokepoints; a guard protects only where it runs (df-5961bdb2) pitfall: an ownership defect was fixed for one kernel practice when its class was every kernel practice of every release; the guard that held was the one that read them all (df-36efa8f2, 4b1890f) - invariants: a defect carries its class and origin, a defect's close names a guard or a decision, src/spec/the defect floor names closes and repeats + pitfall: the parse store's defences were checks written at each of its file system calls, and three blind reviews in a row found one more call without its check; one gateway, unexported and held by a parse of its module, was the fix that held (ca263d3, df-8b32c22b) + pitfall: the gateway's totality oracle read only node:fs imported by name, so a require made with createRequire and the file system asked of process.getBuiltinModule each wrote past it with the test green (df-69c8ab4d) + pitfall: a recursion over a parse tree was kept when its function was rewritten, so a file nested deep enough crashed every reading (df-6e6c2b80) + pitfall: src/plugins, home of the parse store, collected 26 defects in 7 classes over 11 commits of blind review, each round closed by a check at the site its reviewer found and a test that the check existed, and the next round found faults in those checks (df-7c50adfe, df-aad5bf07, df-8b32c22b, df-2456bd98, df-69c8ab4d, df-ff68d46c, df-586f6367); the representation was the defect, a security-relevant cache inside the untrusted repository kept as mutable shared state, and nothing said so until the dead-end reading + invariants: a defect carries its class and origin, a defect's close names a guard or a decision, src/spec/the defect floor names closes and repeats, src/spec/a subsystem at a dead end is named reach: kernel - because: a defect found and fixed once is paid for once and found again; classified, swept, guarded and refuted, it buys protection for its whole class, and the convergence reading can show whether the project is converging + because: a defect found and fixed once is paid for once and found again; a fix that leaves the code no way to express it holds every site at once, and its guard fails the moment a second way appears, so the convergence reading can show whether the project is converging - hand back delegated work: A delegated agent's choices, limits and accepted risks are journal records its report cites, so the coordinator and every later reader see them where the project keeps its decisions, not only in one report read once. when: explicit step: record each choice the brief did not fix as a decision, with the alternative in --over and the cost in --because @@ -29,3 +35,23 @@ learned: df-384acb1e reach: internal because: a report is a transcript, read once by one reader; a journal record carries its rejected alternative and reaches Scope, the pull request's records summary and every later session +- keep state where it is true: Each piece of state a program keeps has one home, chosen for who may write it and how long it must live, and everything else that depends on it is computed from it, not stored beside it. + when: defect duplicated-fact | explicit + step: name the state the change touches: each truth (what is observed, entered or decided) and each value derived from one (a count, a cache, an index, a copy, a version repeated across files, a number written in a document) + leaves: the truths and the derivations, each derivation naming the truth it comes from + step: store each truth once: where a second copy exists, compute it from the first (when built, read or shown) or remove it; a copy that must be kept (a cache, a snapshot) is filed by the truth it came from, by its digest or fingerprint, so it cannot disagree without being read as another + leaves: each truth's one home, and each derivation's function or key + step: choose where state lives by who may write it and how long it lives: never where a party you do not trust can write (a tool's cache inside the project it reads), never a file two processes change in place; prefer records written once, whole, and never changed, over a file edited in turn + leaves: each store's location, who may write it, and whether anything in it changes once written + step: make every output a function of the state: the same data gives the same answer whatever the time, the load, or what a process did before; where a reading must stop early (a time budget), it stops by what it counted and names what it did not read + leaves: each output's inputs, and each place it can differ on the same data, removed or named + step: hold it with an invariant that recomputes each kept derivation from its truth and fails on a difference, or fails where a second writer of a truth appears; and record the choice of each store's home as a decision + leaves: the invariant's / and its refutation, and the decision's id + pitfall: Coherence kept its parse cache inside each project it read, so a repository could write the cache's files, and four rounds of blind review found about thirty defects in its defences; moved to the user's own cache, filed by the text's digest and written once, the defences were no longer needed (d-d1229127) + pitfall: one version was kept in eight files, the package's and seven plugin manifests, and a prerelease checked them against each other because nothing derived them (df-089ac5a9, w-d112a3e4) + pitfall: a journal kept per worktree showed one copy of a session's records, and the pane that read it showed nearly none (w-4c76c5ea) + pitfall: numbers typed into documents and decisions from a measurement went stale or wrong, and had to be corrected by later decisions (d-2dfb13fc, d-e8f43329) + pitfall: a reading stopped by a time budget gave different answers on the same checkout under different machine load (w-77d2fe8f) + invariants: src/spec/a practice fires on a defect's class + reach: kernel + because: data is the job a program does: state kept in two places disagrees, state kept where another party writes is theirs, and an output that is not a function of its state cannot be checked; store truth once, then compute what follows from it (after "Data is destiny", accord.exchange, CC BY-SA 4.0) diff --git a/src/journal/Journal.spec.md b/src/journal/Journal.spec.md index 42d5bdd1..ed3a1c09 100644 --- a/src/journal/Journal.spec.md +++ b/src/journal/Journal.spec.md @@ -189,6 +189,20 @@ Compression: append-only files per session of attributed, durable outcomes, a ne checklist: durable-dispatch-intent dismissed: nothing is dispatched after the append checklist: declared-target-coverage dismissed: one session file, no fan-out checklist: completion-evidence dismissed: the append is complete when the call returns, or nothing is written +- a defect names its component: defect refuses a record that says nothing of where it lies, naming what to pass: --file for each file of the fault, --component, or --unplaced with why no file or component of the project holds it, which is written and counts toward no subsystem. --component is refused unless it names a folder holding a spec that owns every file the defect names, a file's owner being the deepest component folder above it, decided on the path with every . and .. resolved; without it the record carries the one component that owns every file it names, and none when its files have several owners or when one lies in no component or outside the project, the verb saying why. A defect whose files lie in several components counts toward each, so --component cannot narrow it to one. A record written before the field is read as written, and the dead-end reading places it by its files, else its guard, and counts how many it placed that way and how many it could not. + over: a defect whose files lie in one component at two depths, one given --component with a trailing slash, one whose files lie in two components, one with no file, component or --unplaced, one --unplaced with its why, with a file, and blank, a --component naming no component, a --component that owns none of the files, one naming one of two components' files, one beside a file in no component, a --component given another component's file through a .. segment, one that owns every file, a file in no component and one outside the project without --component, and records written before the field: with a file, with none closed under a guard, with a dotted path, with a file closed under another component's guard, and with a file in no component + via: a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so + because: the dead-end reading had to work out a defect's subsystem from its optional files, and 23 of the parse store's defects named none; a component settled at the write is queried rather than inferred (d-777c1614), and the store is append-only, so older records keep no field and are placed by derivation, counted rather than dropped. A --component never checked against the files let an agent move a defect out of the subsystem that holds the fault by accident, and a file in no component was passed over while the record claimed a component owning every file; the files decide, so a wrong component cannot be written (d-a5c35add, d-460d19b7), and gadget/../widget/knob.ts is widget's file (d-dcf35550). 20 defects in this repository's journal named no file and counted toward no subsystem; asking at the write leaves that accident no way to happen (d-540ad200, d-9d919dd8) + crossing: project-source -> record + refuted: made the defect verb accept a --component another component's files contradict -> "a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so" went red in src/journal/defects.test.ts on its own assertion (exit 0 where 1 was expected); separately, let it pass over a file in no component -> red on the record written as widget's; each restored (cmp), green batched and alone (2026-10-27); later, let the defect verb write a defect with no --file, --component or --unplaced -> red on the refusal (exit 0 where 1 was expected); separately, decided a --file's owner on the path as written, its .. unresolved -> red on the dotted path; separately, placed a defect whose files name a component in its guard's component too -> red on "its files, else its guard"; each restored (cmp), green batched and alone (2026-10-27) + kinds: none +- the journal is read from every worktree: loadJournalAcrossWorktrees reads the journal of the checkout it runs in and of every other worktree git lists for the repository (the project's own folder in each, a bare, prunable or missing worktree left out), each record once by id; it reads every store file and skips one only when its bytes equal a file already read (their sha256 digests agree), never by its name or size, reports a store file it cannot read as damaged, the checkout's own included, without letting it stand for another, and writes nothing into any worktree; what it parsed is kept in the user's cache by each file's identity, a derivation the files override: a file whose identity changed is read again, and an index that will not parse is read as none; it names each worktree read with how many records it held that no worktree before it did. Every verb that answers or cites an earlier record resolves its id in the same journals, so a remedy the dead-end reading prints works from the checkout it speaks in; one of them refuses while a store file of its own checkout cannot be read. + over: a repository with a second worktree, a record committed before the worktree was added so both hold it, a defect recorded only in the second, a legacy store file of one name and size in both with different records, an unreadable store file in a third beside a readable one of its name and another in the reading checkout's own journal, a prunable worktree with a journal in its folder, a locked worktree whose folder is gone, a bare repository's worktree beside a journal inside the bare repository, a project nested in a subfolder of its repository whose other worktree holds a journal at its top and in the project's folder, an append to another worktree's file after a reading, an index overwritten with what is no JSON, and escalate --cite, classify and acknowledge run in one checkout on records only another worktree holds, one already answered there + via: the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading + because: an agent records its defects in the checkout it works in, so a reading of one checkout missed the worktree where the work went wrong; this session's records were spread across coherence-beta-fixes-2, agent worktrees and the main checkout (d-b66c7fec). Skipping a file by its name and size dropped a different file of equal size, and an unreadable file hid its namesakes elsewhere; the bytes decide (d-5a93b730). An unreadable file of the checkout's own stopped spec --check (d-8f125f71); the remedy's escalate --cite and acknowledge failed from the checkout orient spoke in (d-d0dad6f0); and every orient and spec --check read 11,000 store files, 143 MB over 116 worktrees, for 1,700 distinct records (d-7fb02821) + crossing: record -> reading + refuted: made loadJournalAcrossWorktrees skip a store file whose length equals one already read without comparing its bytes -> "the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading" went red in src/journal/defects.test.ts on its own assertion (the second legacy record dropped); separately, kept a worktree git calls prunable -> red on its record read; each restored (cmp), green batched and alone (2026-10-27); later, read each other worktree at its top instead of the project's folder in it -> red on the nested project; separately, resolved answering and cited ids in this checkout's journal alone -> red on escalate --cite of another worktree's defect; separately, read the checkout's own journal through loadJournal first -> red, EISDIR on its own unreadable store file; separately, took a kept file from the index whatever its identity -> red on "a file whose identity changed is read again"; each restored (cmp), green batched and alone (2026-10-27) + kinds: none - a shallow clone refuses only an introduced commit it can tell is none: In a shallow clone, defect --introduced with a commit the clone does not hold is written, because its depth may have cut the commit off; it is refused only when the hash names some other object the clone holds, or more than one; the same check, in commits.ts, answers a practice's cited commit. over: a depth-1 clone given an older commit its depth cut off, and the hash of a file it holds via: a shallow clone refuses only an --introduced git can tell is no commit @@ -234,7 +248,7 @@ Compression: append-only files per session of attributed, durable outcomes, a ne because: resolved closes both, and a trigger on the verb alone delivered the whole practice when a conjecture was resolved, which the session then recorded with every step skipped (df-ebbc84e3); recording and classifying a defect keep firing it, since classifying is its first step and a defect is recorded where that step is taken; the sweep found defect firing it as a noun in reads, and the defect verb's next word is free text no pattern can narrow, so that trigger names the program before the verb refuted: made a glob word of a command trigger match any word, so resolved df-* fired on resolving a conjecture as the bare verb did -> "close a defect fires on resolving a defect and never a conjecture, nor on a quoted argument or a heredoc's body" went red in defects.test.ts on its own assertion; restored byte for byte, green batched and alone (2026-10-08) kinds: none -- the convergence reading never infers: query convergence reads the journal, the spec model, git and the kept hook times over a window, 14 days unless --days says otherwise, and reports defects arriving by origin (fix-induced, pre-existing, unknown) and by catch and class, escapes per release (introduced, by commit or by the pull request a merge subject names, inside a release's range and recorded after its tag), closes with a guard, repeats per class, bullets at each day and tag, the files most often changed, and hook latency p50 and p95 per event and Coherence version; a field a record lacks is counted as unknown. +- the convergence reading never infers: query convergence reads the journal, the spec model, git and the kept hook times over a window, 14 days unless --days says otherwise, and reports defects arriving by origin (fix-induced, pre-existing, unknown) and by catch and class, escapes per release (introduced, by commit or by the pull request a merge subject names, inside a release's range and recorded after its tag), closes with a guard, repeats per class, the dead ends (src/spec/a subsystem at a dead end is named), bullets at each day and tag, the files most often changed, and hook latency p50 and p95 per event and Coherence version; a field a record lacks is counted as unknown. over: a project with two release tags, defects introduced by a commit and by a pull request after the second tag, one pre-existing, one with no fields, a guarded close, a close with neither, a repeat, and hook times with a version, without one, and outside the window via: query convergence counts arrivals by origin and catch, escapes per release, closes and repeats, bullets at each tag and hook latency per version, and says unknown wherever a record does not say because: whether discoveries repay is a trend no single record shows; a reading that guessed an old record's origin or version would report the convergence it was built to measure rather than the one the records hold diff --git a/src/journal/cli.ts b/src/journal/cli.ts index ad23dba8..017b10e3 100644 --- a/src/journal/cli.ts +++ b/src/journal/cli.ts @@ -7,7 +7,7 @@ * node src/cli.ts resolved --because "" [--as ""] (a defect: [--guard /] [--decision ]) * node src/cli.ts classify [--class ] [--introduced ] [--caught ] --because "" * node src/cli.ts dismiss --because "" - * node src/cli.ts defect "" --evidence "" [--file ]... + * node src/cli.ts defect "" --evidence "" (--file ... [--component ] | --component | --unplaced "") * node src/cli.ts experiment create "" [--context ]... --action ""... --success ""... * node src/cli.ts experiment close --result =... (result: one of STEP_RESULTS) * node src/cli.ts unable "" --because "" @@ -153,7 +153,7 @@ export const journalVerbs: Record = { export const JOURNAL_USAGE = [ WORK_USAGE, "journal verbs (each needs --session --agent ; a write binds to the one active order its session owns, or to --work ):", - " (--cite , repeatable, names an earlier journal or work record this one rests on or is about, here or committed on another branch; an id found nowhere refuses the write)", + " (--cite , repeatable, names an earlier journal or work record this one rests on or is about, in any worktree's journal or committed on another branch; an id found nowhere refuses the write)", " (--human records words the agent attributes to a human, apart from its own because; it is not proof a human wrote them)", ' decide "" [--over ""]... --because "" [--human ""] [--cite ]...', ' retract --because ""', @@ -162,8 +162,9 @@ export const JOURNAL_USAGE = [ ` resolved --because "" [--guard /] [--decision ] [--class ] [--introduced ] [--caught <${alternation(CAUGHT)}>]`, ' a defect\'s close owes a guard for its class (an invariant whose refutation is witnessed) or a decision saying why the fix suffices; spec --check names a close with neither', ' dismiss --because ""', - ` defect "" --evidence "" [--file ]... [--class ] [--introduced ] [--caught <${alternation(CAUGHT)}>] [--cite ]...`, + ` defect "" --evidence "" (--file ... [--component ] | --component | --unplaced "") [--class ] [--introduced ] [--caught <${alternation(CAUGHT)}>] [--cite ]...`, ' --class is a kebab-case name declared once as the property "class " of defect in a lexicon; give all three: they are what the convergence reading counts', + ' where it lies is required: --file for each file of the fault, or --component; --unplaced "" only when no file or component of the project holds it, since such a defect counts toward no dead end', ' classify [--class ] [--introduced <...>] [--caught <...>] --because "" [--over ""]... a decision citing the defect; the defect is never edited', ' experiment create "" [--context ]... --action ""... --success ""... [--cite ]...', ` experiment close --result =<${alternation(STEP_RESULTS)}>...`, diff --git a/src/journal/convergence.ts b/src/journal/convergence.ts index 6fff1739..5d311b63 100644 --- a/src/journal/convergence.ts +++ b/src/journal/convergence.ts @@ -8,6 +8,8 @@ * range and that were recorded after the release's tag; * the share of closed defects closed with a guard; * repeats per class: guard failures, which should fall to zero; + * dead ends: subsystems that keep collecting defects after their first + * guard, across classes and rounds (dead-ends.ts), read off the same floor; * bullets over time, from the specs at each day and tag; * hotspot churn: the files most often changed; * hook latency p50 and p95 per event per Coherence version. @@ -25,9 +27,11 @@ import { parseSpec } from "../spec/grammar.ts"; import { guardStanding, loadSpecModel } from "../spec/model.ts"; import { HOOK_TIMES_DIR, parseHookTimes } from "../lifecycle/hook-latency.ts"; import { defectStates, type DefectFloor, type DefectState } from "./defects.ts"; +import { DEAD_END, deadEndLine, readDeadEnds, readingScope, windowOf, type DeadEndReading } from "./dead-ends.ts"; import { loadJournal } from "./store.ts"; -export const DEFAULT_WINDOW_DAYS = 14; +/** The window's default length: the dead-end reading's, since both read one window (windowOf). */ +export const DEFAULT_WINDOW_DAYS: number = DEAD_END.days; const DAY_MS = 24 * 60 * 60 * 1000; const UNKNOWN = "unknown"; @@ -90,6 +94,8 @@ export interface Convergence { closing: { recordedInWindow: number; closed: number; guarded: number; decided: number; neither: number; guardedShare: number | null; allTime: Pick }; /** Guard failures by class, all time and in the window. */ repeats: { class: string; allTime: number; inWindow: number }[]; + /** Subsystems at a dead end as of now, read as spec --check reads them (this reading's window, every worktree's journal, dead-ends.ts). */ + deadEnds: DeadEndReading; /** Defects whose introduced names a commit or pull request git could not place in any release range. */ unplaced: string[]; churn: { file: string; commits: number }[]; @@ -191,9 +197,10 @@ export interface ConvergenceOptions { export function convergence(root: string, options: ConvergenceOptions = {}): Convergence { const days = options.days ?? DEFAULT_WINDOW_DAYS; const now = (options.now ?? (() => new Date()))(); - const toDay = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())); - const fromDay = new Date(toDay.getTime() - (days - 1) * DAY_MS); - const from = fromDay.toISOString(); + // One window for this reading and the dead ends it reports: whole days ending today (dead-ends.ts). + const window = windowOf(now, days); + const from = window.from; + const fromDay = new Date(from); const states = defectStates(loadJournal(root).records); const inWindow = states.filter((d) => d.at >= from); @@ -298,7 +305,7 @@ export function convergence(root: string, options: ConvergenceOptions = {}): Con .sort((a, b) => a.event.localeCompare(b.event) || a.version.localeCompare(b.version, undefined, { numeric: true })); return { - window: { days, from: from.slice(0, 10), to: toDay.toISOString().slice(0, 10) }, + window: { days, from: from.slice(0, 10), to: window.to }, arrivals, days: dayList, releases, @@ -312,6 +319,7 @@ export function convergence(root: string, options: ConvergenceOptions = {}): Con allTime: { recorded: floor?.recorded ?? states.length, closed: floor?.closed ?? 0, guarded: floor?.guarded ?? 0, decided: floor?.decided ?? 0 }, }, repeats: [...repeatMap.entries()].map(([cls, n]) => ({ class: cls, ...n })).sort((a, b) => b.allTime - a.allTime), + deadEnds: readDeadEnds(root, model.components, now, { days }), unplaced, churn, hookLatency, @@ -345,6 +353,8 @@ export function convergenceText(c: Convergence): string { const share = k.guardedShare === null ? "no close yet" : `${Math.round(k.guardedShare * 100)}% guarded`; lines.push(`closing: ${k.closed} of ${k.recordedInWindow} closed in the window (${k.guarded} guarded, ${k.decided} decided, ${k.neither} with neither; ${share}); all time ${k.allTime.closed} of ${k.allTime.recorded} closed, ${k.allTime.guarded} guarded`); lines.push(`repeats (guard failures, should fall to zero): ${c.repeats.length === 0 ? "none" : c.repeats.map((r) => `${r.class} ${r.allTime} (${r.inWindow} in the window)`).join(", ")}`); + lines.push(`dead ends (a subsystem collecting defects across classes and rounds after its first guard, its arrivals rising round over round): ${c.deadEnds.deadEnds.length === 0 ? "none" : c.deadEnds.deadEnds.length}; ${readingScope(c.deadEnds)}`); + for (const d of c.deadEnds.deadEnds) lines.push(` ${deadEndLine(d)}`); const first = c.days.find((d) => d.bullets !== undefined)?.bullets; const last = [...c.days].reverse().find((d) => d.bullets !== undefined)?.bullets; if (first !== undefined && last !== undefined) lines.push(`bullets: ${first.bullets} at ${first.commit} -> ${last.bullets} at ${last.commit}; enforced (enforcement and kinds; refutation is in the run store, not read at a past commit) ${first.enforced} -> ${last.enforced}, requirements ${first.requirements} -> ${last.requirements}`); @@ -355,7 +365,7 @@ export function convergenceText(c: Convergence): string { return lines.join("\n"); } -export const CONVERGENCE_USAGE = " query convergence [--days ] [--json] defects arriving by origin and catch, escapes per release, closes with a guard, repeats per class, bullets over time, churn and hook latency per version"; +export const CONVERGENCE_USAGE = " query convergence [--days ] [--json] defects arriving by origin and catch, escapes per release, closes with a guard, repeats per class, dead ends, bullets over time, churn and hook latency per version"; /** query convergence [--days ] [--json] */ export function convergenceCommand(root: string, argv: readonly string[], io: { out: (line: string) => void; err: (line: string) => void }): number { diff --git a/src/journal/dead-ends.ts b/src/journal/dead-ends.ts new file mode 100644 index 00000000..99f9b763 --- /dev/null +++ b/src/journal/dead-ends.ts @@ -0,0 +1,343 @@ +/** + * The dead-end reading: a subsystem that keeps collecting defects after it + * was first guarded, across several classes and several rounds, inside a + * window, with each round bringing more than the rounds before it. A guard + * failure says one class's guard was weaker than claimed; a dead end says the + * subsystem's design is what keeps failing, so each round's local guard is a + * narrower door in a representation that is wrong, and the next round finds + * a fault in the guard itself. + * + * The alarm serves an agent that wants to work helpfully (d-9d919dd8): it + * reads the records such an agent writes in the course of its work, and + * guards against what that agent does by accident, never against an agent + * choosing its records to silence it. So how a defect was closed decides + * nothing: every defect placed in the subsystem after its first guard + * counts, open or closed, closed under a guard it already had or a fresh + * one, or by a decision, since an agent closes each in whatever way fits it. + * A defect with no class counts too, and each as a class of its own, since + * nothing says it shares one: leaving --class off by accident adds to the + * alarm rather than hiding a dead end; spec --check names every unclassified + * defect in its window. A retracted defect counts nowhere: a withdrawn report + * is no fault. What tells a dead end from converging work is the arrivals: + * converging work brings fewer defects each round, while at a dead end each + * round's fixes bring more, so the later half of the rounds brings more than + * the earlier. + * + * A defect's subsystem is the component its record names (the defect verb + * settles it at the write, refuses a component that does not own every file + * the defect names, and refuses a defect that says nothing of where it lies). + * A record older than that field, or written with files in several + * components, is placed by derivation, and the reading says how many it + * derived: each component holding a file it names, else the component its + * close's guard names, the root only when nothing deeper is named. One that + * names neither is placed nowhere and counted as such; nothing is inferred + * from its prose. + * + * The journal is read across every worktree of the repository + * (loadJournalAcrossWorktrees), each record once: an agent at a dead end + * records its defects in the checkout it works in. + * + * A subsystem's count starts at its first guard: the earliest close of one of + * its defects that names a guard whose refutation is witnessed. Families count + * here as classes do: a family exempts a defect from guard-failure counting, + * but a dead end spans classes and families alike. A round is the commit HEAD + * named when the defect was written: a review round's fixes land before the + * next round's findings, so the findings of one round share a commit. The + * window is the convergence reading's (windowOf): whole days ending today. + * + * The reading is derived, never stored: an escalation is a record an agent + * writes under its own session, so Coherence asks for one and never writes it. + * A human's acknowledgement of an escalation that cites a subsystem's defect + * answers it, and only one that carries the human's words (--human) does, since + * any agent can acknowledge: the count starts again after it, so a subsystem + * that keeps failing after the human chose trips it again. + */ + +import { citesOf, type Acknowledgement, type JournalRecord } from "./record.ts"; +import { defectStates, type DefectState, type GuardStanding } from "./defects.ts"; +import { loadJournalAcrossWorktrees, type WorktreeRead } from "./store.ts"; +import { componentHolding, guardStanding, projectFile, type Component } from "../spec/model.ts"; + +/** + * The thresholds a dead end must cross, tuned on Coherence's own journal by + * replaying it every six hours of its history: the parse store crossed every + * one by its ninth round of blind review, and no other component did at any + * point, src/lifecycle and src/readings/scope included, whose arrivals fell + * round over round at their peaks. + */ +export const DEAD_END = { + /** The window's length in days, today included: the convergence reading's window, one function for both (windowOf). */ + days: 14, + /** Defects in the subsystem since its first guard, open or closed, however closed. */ + defects: 8, + /** Distinct classes and families among them, each unclassified defect counting as one more. */ + classes: 3, + /** Distinct commits they were recorded at. */ + rounds: 3, + /** How many more defects the later half of the rounds brought than the earlier half: arrivals that rise, where converging work's fall. */ + rise: 1, +} as const; + +/** + * The window a reading covers: the given number of whole days ending today, + * from the start of the first day in UTC. The dead-end reading and the + * convergence reading both take theirs from here, so they name one window. + */ +export function windowOf(now: Date, days: number): { days: number; from: string; to: string } { + const today = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()); + return { days, from: new Date(today - (days - 1) * DAY_MS).toISOString(), to: new Date(today).toISOString().slice(0, 10) }; +} + +export interface DeadEnd { + /** The component folder. */ + subsystem: string; + /** The close that first guarded it: the guard it named, the close, the defect it closed and when. */ + since: { guard: string; resolution: string; defect: string; at: string }; + /** The human's acknowledgement whose answer restarted the count, when a human answered an earlier dead end here. */ + answered?: string; + /** The defects counted, oldest first: every one placed here after the count started, open or closed, however closed. */ + defects: { id: string; at: string; class?: string; commit: string | null }[]; + /** Each class or family among them with its count, most first. */ + classes: { name: string; count: number }[]; + /** How many of them carry no class: counted as defects, and each as a class of its own. */ + unclassified: number; + /** Each commit they were recorded at with how many, in the order their first defect arrived; null where no git answered. */ + rounds: { commit: string | null; defects: number }[]; + /** The arrivals of the earlier half of the rounds and of the later half (the middle round of an odd number in neither): a dead end's later rounds bring more. */ + trend: { earlier: number; later: number }; + window: { days: number; from: string; to: string }; + /** An escalation nobody has acknowledged that cites one of the counted defects. */ + escalation?: string; +} + +export interface DeadEndOptions { + /** Every component folder of the project, "." for the root. */ + folders: readonly string[]; + /** The component folder holding a project-relative file: the spec model's own answer, so the reading never places a file another way. */ + holding: (file: string) => string | undefined; + /** The project root: an absolute file inside it is read as its project-relative path, and one outside it is placed nowhere. */ + root: string; + standing: (guard: string) => GuardStanding; + now: Date; + thresholds?: Partial>; +} + +const DAY_MS = 24 * 60 * 60 * 1000; + +/** How a defect was placed: by the component its record names, derived from its files or its guard, or nowhere. */ +export type Placement = "recorded" | "files" | "guard" | "unplaced"; + +/** + * The subsystems a defect belongs to and how they were found: the component + * its record names; else each component below the root holding a file it + * names (each path read with its "." and ".." resolved, projectFile); else + * the component below the root its close's guard names; else the root, when + * a file or the guard named it; else nowhere. Its files, else its guard: a + * guard closes a defect from wherever its invariant is declared, so it names + * where the defect lies only when the defect names no file that does. + */ +export function placeDefect(state: DefectState, options: Pick): { subsystems: string[]; by: Placement } { + if (state.component !== undefined) return { subsystems: [state.component], by: "recorded" }; + const files = new Set(); + for (const named of state.files ?? []) { + const file = projectFile(options.root, named); + const folder = file === undefined ? undefined : options.holding(file); + if (folder !== undefined) files.add(folder); + } + const deeper = [...files].filter((f) => f !== ".").sort(); + if (deeper.length > 0) return { subsystems: deeper, by: "files" }; + const guard = state.resolution?.guard; + const guarded = guard === undefined ? undefined : guard.slice(0, Math.max(0, guard.lastIndexOf("/"))); + const byGuard = guarded !== undefined && options.folders.includes(guarded) ? guarded : undefined; + if (byGuard !== undefined && byGuard !== ".") return { subsystems: [byGuard], by: "guard" }; + if (files.has(".")) return { subsystems: ["."], by: "files" }; + if (byGuard === ".") return { subsystems: ["."], by: "guard" }; + return { subsystems: [], by: "unplaced" }; +} + +const byTime = (a: T, b: T): number => (a.at < b.at ? -1 : a.at > b.at ? 1 : 0); + +/** An acknowledgement that carries a human's words: the only answer that restarts a count, since any agent can acknowledge. */ +const human = (r: JournalRecord): r is Acknowledgement => r.kind === "acknowledgement" && typeof r.human === "string" && r.human.trim() !== ""; + +/** + * Every subsystem the journal shows at a dead end as of now, most defects + * first. spec --check, orient and the convergence reading each call it + * through readDeadEnds, with the same journal, components and window, so + * they never disagree. + */ +export function deadEnds(records: readonly JournalRecord[], states: readonly DefectState[], options: DeadEndOptions): DeadEnd[] { + const limits = { ...DEAD_END, ...options.thresholds }; + const to = options.now.toISOString(); + const window = windowOf(options.now, limits.days); + // Only what was written by now: a later record, or a close written after now, is no part of this reading. + const written = records.filter((r) => r.at <= to); + const gone = new Set(written.flatMap((r) => (r.kind === "retraction" ? [r.of] : []))); + const escalations = written.filter((r) => r.kind === "escalation" && !gone.has(r.id)); + const answers = written.filter(human).filter((a) => !gone.has(a.id)); + const acknowledged = new Set(written.flatMap((r) => (r.kind === "acknowledgement" && !gone.has(r.id) ? [r.of] : []))); + const known = states.filter((s) => s.at <= to).map((s): DefectState => { + if (s.resolution === undefined || s.resolution.at <= to) return s; + const { resolution: _later, ...open } = s; + return open; + }); + + const bySubsystem = new Map(); + for (const state of known) { + for (const subsystem of placeDefect(state, options).subsystems) bySubsystem.set(subsystem, [...(bySubsystem.get(subsystem) ?? []), state]); + } + + const found: DeadEnd[] = []; + for (const [subsystem, mine] of bySubsystem) { + // The first guard: the earliest close among the subsystem's defects naming a guard whose refutation is witnessed. + let first: DeadEnd["since"] | undefined; + for (const s of mine) { + const r = s.resolution; + if (r?.guard === undefined || options.standing(r.guard) !== "witnessed") continue; + if (first === undefined || r.at < first.at) first = { guard: r.guard, resolution: r.id, defect: s.id, at: r.at }; + } + if (first === undefined) continue; + // A human's answer to an escalation about this subsystem restarts the count after it. + const ids = new Set(mine.map((s) => s.id)); + const about = new Set(escalations.filter((e) => citesOf(e).some((id) => ids.has(id))).map((e) => e.id)); + const answer = answers.filter((a) => about.has(a.of)).sort(byTime).at(-1); + const start = [first.at, window.from, answer?.at ?? ""].sort().at(-1)!; + // Every defect after the start counts, whatever its close says: open, closed under a guard already here or a fresh one, or decided. + const counted = mine.filter((s) => s.at > start).sort(byTime); + const classCounts = new Map(); + for (const s of counted) if (s.class !== undefined) classCounts.set(s.class, (classCounts.get(s.class) ?? 0) + 1); + const unclassified = counted.filter((s) => s.class === undefined).length; + const perRound = new Map(); + for (const s of counted) perRound.set(s.commit ?? null, (perRound.get(s.commit ?? null) ?? 0) + 1); + const rounds = [...perRound.entries()].map(([commit, defects]) => ({ commit, defects })); + // Arrivals per round, earlier half against later half: converging work brings fewer each round, a dead end more. + const half = Math.floor(rounds.length / 2); + const sum = (part: typeof rounds): number => part.reduce((n, r) => n + r.defects, 0); + const trend = { earlier: sum(rounds.slice(0, half)), later: sum(rounds.slice(rounds.length - half)) }; + // An unclassified defect could be of any class, so each counts as a class of its own: leaving --class off never keeps a subsystem under the threshold. + const kinds = classCounts.size + unclassified; + if (counted.length < limits.defects || kinds < limits.classes || rounds.length < limits.rounds || trend.later - trend.earlier < limits.rise) continue; + const countedIds = new Set(counted.map((s) => s.id)); + // Awaiting a human: an escalation nobody has acknowledged. One an agent acknowledged without a human's words is answered as an escalation but restarts nothing here, so the reading asks again. + const open = escalations.find((e) => !acknowledged.has(e.id) && citesOf(e).some((id) => countedIds.has(id))); + found.push({ + subsystem, + since: first, + ...(answer === undefined || answer.at <= first.at ? {} : { answered: answer.id }), + defects: counted.map((s) => ({ id: s.id, at: s.at, ...(s.class === undefined ? {} : { class: s.class }), commit: s.commit ?? null })), + classes: [...classCounts.entries()].map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count || a.name.localeCompare(b.name)), + unclassified, + rounds, + trend, + window: { days: window.days, from: window.from.slice(0, 10), to: window.to }, + ...(open === undefined ? {} : { escalation: open.id }), + }); + } + return found.sort((a, b) => b.defects.length - a.defects.length || a.subsystem.localeCompare(b.subsystem)); +} + +/** What a dead end counted, as one phrase: the defects, the classes, the rounds and their arrivals, the first guard and the window. */ +function counted(d: DeadEnd): string { + const kinds = [...d.classes.map((c) => `${c.name} ${c.count}`), ...(d.unclassified === 0 ? [] : [`${d.unclassified} unclassified, each a class of its own`])]; + return ( + `${d.defects.length} defects across ${d.classes.length + d.unclassified} classes (${kinds.join(", ")}) over ${d.rounds.length} rounds whose arrivals rise ` + + `(${d.rounds.map((r) => r.defects).join(", ")} a round; ${d.trend.later} in the later half against ${d.trend.earlier} in the earlier), ` + + `open or closed alike, since its first guard, "${d.since.guard}" (${d.since.resolution} closed ${d.since.defect} on ${d.since.at.slice(0, 10)}), in the ${d.window.days} days from ${d.window.from} to ${d.window.to}` + ); +} + +/** What to do: stop guarding, review the representation, and ask a human, or say the question already waits on one. */ +function remedy(d: DeadEnd): string { + const stop = `Stop adding guards to ${d.subsystem} and review its representation: weigh a different design before a narrower door in this one, and record the choice as a decision`; + if (d.escalation !== undefined) return `${stop}; escalated as ${d.escalation}, awaiting a human (acknowledge ${d.escalation} --human "" --because ""; only an acknowledgement carrying --human restarts the count)`; + return `${stop}; ask a human whether to redesign it: escalate "${d.subsystem} is at a dead end: redesign it or keep guarding?" --because "" --cite ${d.defects.at(-1)!.id}`; +} + +/** The dead-end reading of a project: the dead ends, the worktrees whose journals it read, how it placed each defect, and the defects in its window that carry no class. */ +export interface DeadEndReading { + deadEnds: DeadEnd[]; + worktrees: WorktreeRead[]; + /** Defects by how they were placed: the component their record names, derived from their files or guard, or nowhere. */ + placement: Record; + /** Lines of a journal, in any worktree, that would not parse, and store files that could not be read. */ + damaged: number; + /** The window every count reads, from its first day to today. */ + window: { days: number; from: string; to: string }; + /** Defects recorded in the window that carry no class, oldest first: each answers to no guard, so the reading names them. */ + unclassified: string[]; +} + +/** + * The reading spec --check, orient and the convergence reading share: the + * journal of every worktree, placed by the spec model's components and graded + * by its guards, as of now, over the window the thresholds' days give. + */ +export function readDeadEnds(root: string, components: readonly Component[], now: Date = new Date(), thresholds?: DeadEndOptions["thresholds"]): DeadEndReading { + const loaded = loadJournalAcrossWorktrees(root); + const states = defectStates(loaded.records); + const options: DeadEndOptions = { + folders: components.map((c) => c.folder), + holding: (file) => componentHolding(components, file)?.folder, + root, + standing: guardStanding(components), + now, + ...(thresholds === undefined ? {} : { thresholds }), + }; + const placement: Record = { recorded: 0, files: 0, guard: 0, unplaced: 0 }; + for (const state of states) placement[placeDefect(state, options).by] += 1; + const window = windowOf(now, thresholds?.days ?? DEAD_END.days); + const to = now.toISOString(); + const unclassified = states.filter((s) => s.class === undefined && s.at >= window.from && s.at <= to).map((s) => s.id); + return { + deadEnds: deadEnds(loaded.records, states, options), + worktrees: loaded.worktrees, + placement, + damaged: loaded.damaged.length, + window: { days: window.days, from: window.from.slice(0, 10), to: window.to }, + unclassified, + }; +} + +/** How many worktrees holding records no other did, and how many unclassified defects, a line names by path or id. */ +const NAMED = 5; + +/** Which journals the reading read, how it placed the defects and which in its window carry no class, as one line: the worktrees that held records no other did are named. */ +export function readingScope(r: DeadEndReading): string { + const own = r.worktrees.filter((w) => !w.self && w.only > 0).sort((a, b) => b.only - a.only || a.path.localeCompare(b.path)); + const named = own.slice(0, NAMED).map((w) => `${w.path} (${w.only})`); + if (own.length > NAMED) named.push(`${own.length - NAMED} more (query convergence --json names each)`); + const p = r.placement; + const u = r.unclassified; + const ids = [...u.slice(0, NAMED), ...(u.length > NAMED ? [`${u.length - NAMED} more`] : [])].join(", "); + return ( + `read the journals of ${r.worktrees.length} worktree${r.worktrees.length === 1 ? "" : "s"}${own.length === 0 ? "" : `, records only in ${named.join(", ")}`}${r.damaged === 0 ? "" : `, ${r.damaged} unreadable line${r.damaged === 1 ? "" : "s"} or file${r.damaged === 1 ? "" : "s"}`}; ` + + `defects placed by the component their record names ${p.recorded}, derived from their files ${p.files}, from their guard ${p.guard}, unplaced ${p.unplaced}; ` + + `unclassified in the ${r.window.days} days from ${r.window.from} to ${r.window.to} ${u.length}` + + (u.length === 0 ? "" : ` (${ids}): each counts toward a dead end as a class of its own and answers to no guard; classify --class --because ""`) + ); +} + +/** One dead end as spec --check names it: everything counted, every defect by id, then what to do. */ +export function deadEndLine(d: DeadEnd): string { + return `DEAD END ${d.subsystem}: ${counted(d)}: ${d.defects.map((x) => x.id).join(", ")}. ${remedy(d)}`; +} + +/** spec --check's lines: each dead end, then one line of how many and what was read. */ +export function deadEndLines(r: DeadEndReading): string[] { + return [...r.deadEnds.map(deadEndLine), `dead ends: ${r.deadEnds.length}; ${readingScope(r)}`]; +} + +/** + * The dead ends as orient shows them, under a heading, never shortened: the + * human must see the ids whole. With none, nothing: orient injects no total + * (src/lifecycle/no totals are injected), so what the reading read and which + * defects carry no class are spec --check's and the convergence reading's to + * say, and orient speaks only with an alarm, with the counts it rests on. + */ +export function deadEndBlock(r: DeadEndReading): string[] { + if (r.deadEnds.length === 0) return []; + return [ + `Dead ends (${r.deadEnds.length}): a subsystem keeps collecting defects after it was guarded, across classes and rounds, and its arrivals rise round over round; more guards there are narrower doors in a design that is wrong. The reading ${readingScope(r)}.`, + ...r.deadEnds.map((d) => `⚠ ${d.subsystem}: ${counted(d)}: ${d.defects.map((x) => x.id).join(", ")}. ${remedy(d)}`), + ]; +} diff --git a/src/journal/defects.test.ts b/src/journal/defects.test.ts index 0bede801..d8917000 100644 --- a/src/journal/defects.test.ts +++ b/src/journal/defects.test.ts @@ -8,7 +8,7 @@ import assert from "node:assert/strict"; import { sessionText } from "./shard-fixture.ts"; import { execFileSync } from "node:child_process"; -import { appendFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { appendFileSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { after, describe, test } from "node:test"; @@ -16,11 +16,13 @@ import { journalVerbs, type Io } from "./cli.ts"; import { defectStates } from "./defects.ts"; import { convergence, convergenceText } from "./convergence.ts"; import type { Decision, Defect, Resolution } from "./record.ts"; -import { loadJournal } from "./store.ts"; -import { loadSpecModel } from "../spec/model.ts"; +import { loadJournal, loadJournalAcrossWorktrees } from "./store.ts"; +import { componentHolding, loadSpecModel } from "../spec/model.ts"; import { specCommand } from "../spec/cli.ts"; import { firedBy, parsePractices } from "../spec/practice.ts"; import { toolUseOf } from "../lifecycle/practice-delivery.ts"; +import { escalationBlock, specBlock } from "../lifecycle/hook.ts"; +import { deadEndLine, deadEnds, placeDefect, readDeadEnds } from "./dead-ends.ts"; // Every fixture folder this file makes is removed when the file is done; the leak guard fails a file that leaves one. const madeFolders: string[] = []; @@ -100,9 +102,9 @@ test("a defect carries a declared class, where it came in and what caught it, an const root = project({ "lexicon.json": JSON.stringify({ concepts: [{ name: "defect", definition: "d", properties: { "class widget-spin": "a widget spins forever" } }] }) }); const sha = commitAll(root, "first", "2026-10-01T10:00:00Z"); const j = journal(root, clock("2026-10-03T00:00:00Z")); - const full = idOf(j("defect", "the knob stuck", "--evidence", "turned it", "--class", "path-identity", "--introduced", sha.slice(0, 7), "--caught", "review", ...WHO)); - const own = idOf(j("defect", "the widget spun", "--evidence", "watched it", "--class", "widget-spin", "--introduced", "PR #12", "--caught", "adopter", ...WHO)); - const bare = idOf(j("defect", "the dial was silent", "--evidence", "listened", ...WHO)); + const full = idOf(j("defect", "the knob stuck", "--evidence", "turned it", "--class", "path-identity", "--introduced", sha.slice(0, 7), "--caught", "review", "--file", "widget/knob.ts", ...WHO)); + const own = idOf(j("defect", "the widget spun", "--evidence", "watched it", "--class", "widget-spin", "--introduced", "PR #12", "--caught", "adopter", "--file", "widget/knob.ts", ...WHO)); + const bare = idOf(j("defect", "the dial was silent", "--evidence", "listened", "--file", "widget/knob.ts", ...WHO)); const records = loadJournal(root).records; const read = (id: string): Defect => records.find((r) => r.id === id) as Defect; assert.deepEqual([read(full).class, read(full).introduced, read(full).caught], ["path-identity", sha.slice(0, 7), "review"]); @@ -110,11 +112,11 @@ test("a defect carries a declared class, where it came in and what caught it, an assert.ok(!("class" in read(bare)) && !("introduced" in read(bare)) && !("caught" in read(bare)), "a defect without them is written as before"); const before = loadJournal(root).records.length; const refused = [ - j("defect", "x", "--evidence", "y", "--class", "made-up-class", ...WHO), - j("defect", "x", "--evidence", "y", "--class", "Not Kebab", ...WHO), - j("defect", "x", "--evidence", "y", "--introduced", "yesterday", ...WHO), - j("defect", "x", "--evidence", "y", "--introduced", "abcdef1234", ...WHO), - j("defect", "x", "--evidence", "y", "--caught", "luck", ...WHO), + j("defect", "x", "--evidence", "y", "--class", "made-up-class", "--file", "widget/knob.ts", ...WHO), + j("defect", "x", "--evidence", "y", "--class", "Not Kebab", "--file", "widget/knob.ts", ...WHO), + j("defect", "x", "--evidence", "y", "--introduced", "yesterday", "--file", "widget/knob.ts", ...WHO), + j("defect", "x", "--evidence", "y", "--introduced", "abcdef1234", "--file", "widget/knob.ts", ...WHO), + j("defect", "x", "--evidence", "y", "--caught", "luck", "--file", "widget/knob.ts", ...WHO), ]; for (const run of refused) assert.equal(run.code, 1, run.out.join("\n")); assert.match(refused[0]!.err.join("\n"), /declared nowhere; declare it once as the property "class made-up-class" of defect/); @@ -137,7 +139,7 @@ describe("a shallow clone refuses only an --introduced git can tell is no commit const blob = execFileSync("git", ["rev-parse", "HEAD:knob.ts"], { cwd: origin, encoding: "utf8" }).trim(); const root = made(mkdtempSync(join(tmpdir(), "coherence-defects-shallow-"))); execFileSync("git", ["clone", "-q", "--depth", "1", `file://${origin}`, root]); - const run = journal(root, clock("2026-10-03T00:00:00Z"))("defect", "the knob stuck", "--evidence", "turned it", "--introduced", refused ? blob : older, ...WHO); + const run = journal(root, clock("2026-10-03T00:00:00Z"))("defect", "the knob stuck", "--evidence", "turned it", "--introduced", refused ? blob : older, "--file", "widget/knob.ts", ...WHO); assert.equal(run.code, refused ? 1 : 0, run.err.join("\n")); }); } @@ -146,7 +148,7 @@ describe("a shallow clone refuses only an --introduced git can tell is no commit test("classify folds into the defect without editing it: a later classification overrides, a retracted one gives nothing, and a field nobody gave stays unknown", () => { const root = project(); const j = journal(root, clock("2026-10-03T00:00:00Z")); - const d = idOf(j("defect", "the knob stuck", "--evidence", "turned it", "--caught", "self", ...WHO)); + const d = idOf(j("defect", "the knob stuck", "--evidence", "turned it", "--caught", "self", "--file", "widget/knob.ts", ...WHO)); const line = sessionText(join(root, ".coherence", "journal"), "s1"); const first = idOf(j("classify", d, "--class", "cost", "--introduced", "pre-existing", "--because", "the first reading", ...WHO)); const second = idOf(j("classify", d, "--class", "silent-skip", "--because", "a closer reading", ...WHO)); @@ -161,7 +163,7 @@ test("classify folds into the defect without editing it: a later classification assert.ok(second !== first); const state = defectStates(records).find((s) => s.id === d)!; assert.deepEqual([state.class, state.introduced, state.caught], ["silent-skip", "pre-existing", "self"], "the later class wins, the retracted catch gives nothing, the defect's own catch stands"); - const other = idOf(j("defect", "the dial was silent", "--evidence", "listened", ...WHO)); + const other = idOf(j("defect", "the dial was silent", "--evidence", "listened", "--file", "widget/knob.ts", ...WHO)); const blank = defectStates(loadJournal(root).records).find((s) => s.id === other)!; assert.deepEqual([blank.class, blank.introduced, blank.caught], [undefined, undefined, undefined], "nothing is inferred"); assert.equal(j("classify", d, "--because", "nothing given", ...WHO).code, 1, "a classification gives at least one field"); @@ -171,7 +173,7 @@ test("classify folds into the defect without editing it: a later classification test("resolved closes a defect with a guard a spec declares or a decision, refuses a guard or decision that names nothing, and a retracted close can be closed again", () => { const root = project(); const j = journal(root, clock("2026-10-03T00:00:00Z")); - const d = idOf(j("defect", "the knob stuck", "--evidence", "turned it", ...WHO)); + const d = idOf(j("defect", "the knob stuck", "--evidence", "turned it", "--file", "widget/knob.ts", ...WHO)); const c = idOf(j("conjecture", "the knob is cold", "--discriminated-by", "warm it", ...WHO)); const why = idOf(j("decide", "fix the one knob", "--over", "none", "--because", "no other knob has the shape", ...WHO)); assert.match(j("resolved", d, "--because", "oiled", "--guard", "widget/no such bullet", ...WHO).err.join("\n"), /declares no invariant named "no such bullet"/); @@ -196,15 +198,15 @@ test("spec --check names a defect closed with neither a guard nor a decision and const j = journal(root, clock("2026-10-03T00:00:00Z")); witness(root, "widget", "knob turns", "2026-10-02T00:00:00.000Z"); const why = idOf(j("decide", "fix the one dial", "--over", "none", "--because", "no sibling has the shape", ...WHO)); - const first = idOf(j("defect", "the knob stuck", "--evidence", "turned it", "--class", "path-identity", ...WHO)); + const first = idOf(j("defect", "the knob stuck", "--evidence", "turned it", "--class", "path-identity", "--file", "widget/knob.ts", ...WHO)); const guard = idOf(j("resolved", first, "--because", "oiled", "--guard", "widget/knob turns", ...WHO)); - const repeat = idOf(j("defect", "another knob stuck", "--evidence", "turned it", ...WHO)); + const repeat = idOf(j("defect", "another knob stuck", "--evidence", "turned it", "--file", "widget/knob.ts", ...WHO)); idOf(j("classify", repeat, "--class", "path-identity", "--because", "the same shape", ...WHO)); - const neither = idOf(j("defect", "a lever stuck", "--evidence", "pulled it", ...WHO)); + const neither = idOf(j("defect", "a lever stuck", "--evidence", "pulled it", "--file", "widget/knob.ts", ...WHO)); const neitherClose = idOf(j("resolved", neither, "--because", "greased", ...WHO)); - const unwitnessed = idOf(j("defect", "the dial was silent", "--evidence", "listened", ...WHO)); + const unwitnessed = idOf(j("defect", "the dial was silent", "--evidence", "listened", "--file", "widget/knob.ts", ...WHO)); idOf(j("resolved", unwitnessed, "--because", "tightened", "--guard", "widget/dial clicks", ...WHO)); - const decided = idOf(j("defect", "a dial rattled", "--evidence", "shook it", ...WHO)); + const decided = idOf(j("defect", "a dial rattled", "--evidence", "shook it", "--file", "widget/knob.ts", ...WHO)); idOf(j("resolved", decided, "--because", "tightened", "--decision", why, ...WHO)); const out: string[] = []; const code = specCommand([root], { cwd: root, out: (l) => out.push(l), err: (l) => out.push(l) }); @@ -229,13 +231,13 @@ test("query convergence counts arrivals by origin and catch, escapes per release execFileSync("git", ["tag", "v0.2.0"], { cwd: root }); witness(root, "widget", "knob turns", "2026-10-02T12:00:00.000Z"); const j = journal(root, clock("2026-10-03T00:00:00Z")); - const byCommit = idOf(j("defect", "the dial skipped", "--evidence", "e", "--class", "cost", "--introduced", feature.slice(0, 9), "--caught", "review", ...WHO)); - const byPull = idOf(j("defect", "the dial stuck", "--evidence", "e", "--introduced", "PR #7", "--caught", "test", ...WHO)); - idOf(j("defect", "the knob was always loose", "--evidence", "e", "--introduced", "pre-existing", "--caught", "adopter", ...WHO)); - const bare = idOf(j("defect", "something rattled", "--evidence", "e", ...WHO)); + const byCommit = idOf(j("defect", "the dial skipped", "--evidence", "e", "--class", "overmatch", "--introduced", feature.slice(0, 9), "--caught", "review", "--file", "widget/knob.ts", ...WHO)); + const byPull = idOf(j("defect", "the dial stuck", "--evidence", "e", "--introduced", "PR #7", "--caught", "test", "--file", "widget/knob.ts", ...WHO)); + idOf(j("defect", "the knob was always loose", "--evidence", "e", "--introduced", "pre-existing", "--caught", "adopter", "--file", "widget/knob.ts", ...WHO)); + const bare = idOf(j("defect", "something rattled", "--evidence", "e", "--file", "widget/knob.ts", ...WHO)); idOf(j("resolved", byCommit, "--because", "fixed, every dial checked", "--guard", "widget/knob turns", ...WHO)); idOf(j("resolved", bare, "--because", "tightened", ...WHO)); - const repeat = idOf(j("defect", "another dial skipped", "--evidence", "e", "--class", "cost", ...WHO)); + const repeat = idOf(j("defect", "another dial skipped", "--evidence", "e", "--class", "overmatch", "--file", "widget/knob.ts", ...WHO)); mkdirSync(join(root, ".coherence", "hook-times"), { recursive: true }); writeFileSync( join(root, ".coherence", "hook-times", "s.jsonl"), @@ -258,7 +260,7 @@ test("query convergence counts arrivals by origin and catch, escapes per release assert.deepEqual(release.bullets && [release.bullets.bullets, release.bullets.enforced], [2, 2]); assert.deepEqual(c.releases.find((r) => r.tag === "v0.1.0")!.bullets!.bullets, 1); assert.deepEqual([c.closing.closed, c.closing.guarded, c.closing.neither], [2, 1, 1]); - assert.deepEqual(c.repeats, [{ class: "cost", allTime: 1, inWindow: 1 }]); + assert.deepEqual(c.repeats, [{ class: "overmatch", allTime: 1, inWindow: 1 }]); assert.ok(c.repeats.length === 1 && repeat.startsWith("df-")); assert.deepEqual( c.hookLatency.map((h) => [h.event, h.version, h.count, h.p50, h.p95]), @@ -295,13 +297,361 @@ test("a family's guard answers only for its own defect, so a later defect in the const j = journal(root, clock("2026-10-03T00:00:00Z")); witness(root, "widget", "knob turns", "2026-10-02T00:00:00.000Z"); // audience is a family in Coherence's lexicon: too broad for one guard. - const first = idOf(j("defect", "the label named the wrong knob", "--evidence", "read it", "--class", "audience", ...WHO)); + const first = idOf(j("defect", "the label named the wrong knob", "--evidence", "read it", "--class", "audience", "--file", "widget/knob.ts", ...WHO)); idOf(j("resolved", first, "--because", "renamed", "--guard", "widget/knob turns", ...WHO)); - const later = idOf(j("defect", "the manual omits the dial", "--evidence", "read it", "--class", "audience", ...WHO)); + const later = idOf(j("defect", "the manual omits the dial", "--evidence", "read it", "--class", "audience", "--file", "widget/knob.ts", ...WHO)); // The same sequence in a class is still a guard failure. - const classFirst = idOf(j("defect", "the knob stuck", "--evidence", "turned it", "--class", "path-identity", ...WHO)); + const classFirst = idOf(j("defect", "the knob stuck", "--evidence", "turned it", "--class", "path-identity", "--file", "widget/knob.ts", ...WHO)); idOf(j("resolved", classFirst, "--because", "oiled", "--guard", "widget/knob turns", ...WHO)); - const classRepeat = idOf(j("defect", "another knob stuck", "--evidence", "turned it", "--class", "path-identity", ...WHO)); + const classRepeat = idOf(j("defect", "another knob stuck", "--evidence", "turned it", "--class", "path-identity", "--file", "widget/knob.ts", ...WHO)); const model = loadSpecModel(root); assert.deepEqual(model.defects!.guardFailures.map((g) => g.id), [classRepeat], `a later audience defect (${later}) is no guard failure; a later path-identity one is`); }); + +/** A clock two days back from the real now, so the dead-end window, which the model reads from the wall clock, holds the fixture. */ +const RECENT = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(); + +test("spec --check and orient name a subsystem whose defects keep arriving after its first guard across classes, families and rounds, however they closed, and only a human's acknowledgement answers it", () => { + const root = project({ "gadget/Gadget.spec.md": SPEC.replace("# Widget", "# Gadget").replace("Widgets turn.", "Gadgets hum.") }); + commitAll(root, "first", RECENT); + witness(root, "widget", "knob turns", "2026-10-01T00:00:00.000Z"); + witness(root, "widget", "dial clicks", "2026-10-01T00:00:00.000Z"); + witness(root, "gadget", "knob turns", "2026-10-01T00:00:00.000Z"); + const j = journal(root, clock(RECENT)); + const defect = (what: string, cls: string | undefined, ...more: string[]) => idOf(j("defect", what, "--evidence", "seen", ...(cls === undefined ? [] : ["--class", cls]), ...more, ...WHO)); + const close = (id: string, guard: string) => idOf(j("resolved", id, "--because", "a check at the site", "--guard", guard, ...WHO)); + const FILE = ["--file", "widget/knob.ts"]; + const HERE = ["--component", "widget"]; + // Another component guarded first: its guard and its defect are no part of widget's count. + const elsewhere = defect("the gadget hummed off key", "cost", "--file", "gadget/hum.ts"); + close(elsewhere, "gadget/knob turns"); + // Round 0: the first guard. Nothing before it counts. + const first = defect("the knob slipped", "path-identity", ...FILE); + const firstClose = close(first, "widget/knob turns"); + commitAll(root, "round 1", RECENT); + // Round 1: a class closed by the guard the knob already had, and a family left open. + const r1 = [defect("the knob cost a second a turn", "cost", ...HERE), defect("the knob's label named the dial", "audience", ...FILE)]; + close(r1[0]!, "widget/knob turns"); + commitAll(root, "round 2", RECENT); + // Round 2: each closed under a guard the subsystem never named before, or left open: none of it comes back through an old guard. + const r2 = [defect("the knob's check claimed every knob", "over-claim", ...HERE), defect("the dial cost a second", "cost", ...HERE), defect("a linked knob slipped", "path-identity", ...FILE)]; + close(r2[0]!, "widget/dial clicks"); + close(r2[1]!, "widget/dial clicks"); + commitAll(root, "round 3", RECENT); + // Round 3: still more, one with no class at all and two left open. + const r3 = [defect("the manual omits the knob", "audience", ...HERE), defect("the dial's check claimed every dial", undefined, ...FILE), defect("the knob read a half turn", "parse-gap", ...FILE)]; + close(r3[0]!, "widget/dial clicks"); + const counted = [...r1, ...r2, ...r3]; + + const out: string[] = []; + const code = specCommand([root], { cwd: root, out: (l) => out.push(l), err: (l) => out.push(l) }); + const text = out.join("\n"); + const line = text.split("\n").find((l) => l.startsWith("DEAD END widget:")); + assert.ok(line !== undefined, text); + assert.match(line, /widget: 8 defects across 6 classes \(audience 2, cost 2, over-claim 1, parse-gap 1, path-identity 1, 1 unclassified, each a class of its own\) over 3 rounds whose arrivals rise \(2, 3, 3 a round; 3 in the later half against 2 in the earlier\), open or closed alike/); + assert.match(line, new RegExp(`since its first guard, "widget/knob turns" \\(${firstClose} closed ${first} on `)); + const window = readDeadEnds(root, loadSpecModel(root).components).window; + assert.match(line, new RegExp(`in the 14 days from ${window.from} to ${window.to}: `)); + // Every counted defect by id, oldest first: the first guard's own defect starts the count and another component's is no part of it. + assert.deepEqual(/ to \d{4}-\d{2}-\d{2}: ([^.]*)\. /.exec(line)![1]!.split(", "), counted); + assert.ok(!line.includes(elsewhere)); + assert.match(line, /Stop adding guards to widget and review its representation/); + assert.match(line, new RegExp(`escalate "widget is at a dead end: redesign it or keep guarding\\?" --because "" --cite ${r3[2]}`)); + const model = loadSpecModel(root); + assert.equal(model.problems.length, 0, "advisory, never a problem"); + assert.equal(code, 0); + const reading = readDeadEnds(root, model.components); + assert.deepEqual(reading.deadEnds.map((d) => d.subsystem), ["widget"], "gadget has one defect, closed by its first guard"); + assert.deepEqual(reading.deadEnds[0]!.trend, { earlier: 2, later: 3 }); + assert.deepEqual(reading.placement, { recorded: 10, files: 0, guard: 0, unplaced: 0 }, "a defect written with a file or a component names its component"); + assert.deepEqual(reading.unclassified, [r3[1]], "the reading names the defect that carries no class"); + // The unclassified count as a class of their own: at a threshold of six classes it is the sixth. + assert.deepEqual(readDeadEnds(root, model.components, new Date(), { classes: 6 }).deadEnds.map((d) => d.subsystem), ["widget"], "the unclassified defect is the sixth class"); + assert.deepEqual(readDeadEnds(root, model.components, new Date(), { classes: 7 }).deadEnds, []); + // With every class taken away, each defect is a class of its own: leaving --class off never silences it. + const unlabelled = loadJournal(root).records; + const bare = defectStates(unlabelled).map(({ class: _class, ...rest }) => rest); + const options = { folders: ["widget", "gadget"], holding: (f: string) => f.split("/")[0], root, standing: () => "witnessed" as const, now: new Date() }; + assert.deepEqual(deadEnds(unlabelled, bare, options).map((d) => [d.subsystem, d.classes.length, d.unclassified]), [["widget", 0, 8]]); + assert.match(text, new RegExp(`^dead ends: 1; read the journals of 1 worktree; defects placed by the component their record names 10, derived from their files 0, from their guard 0, unplaced 0; unclassified in the 14 days from ${window.from} to ${window.to} 1 \\(${r3[1]}\\): each counts toward a dead end as a class of its own`, "m")); + // A withdrawn report is no fault: with the last round retracted, the rest fall below every threshold. + const records0 = loadJournal(root).records; + const withdrawn = [...records0, ...r3.map((of, i) => ({ id: `r-0000000${i}`, kind: "retraction" as const, at: new Date(Date.now() - 1000).toISOString(), session: "s1", agent: "alpha", commit: null, dirty: false, of, because: "not a defect: the reviewer misread the knob" }))]; + const placedBy = { folders: ["widget", "gadget"], holding: (f: string) => f.split("/")[0], root, standing: () => "witnessed" as const, now: new Date() }; + assert.deepEqual(deadEnds(records0, defectStates(records0), placedBy).map((d) => d.defects.length), [8]); + assert.deepEqual(deadEnds(withdrawn, defectStates(withdrawn), placedBy), [], "a retracted defect counts toward no dead end"); + const orient = specBlock(root); + assert.match(orient, /^Dead ends \(1\): /m); + assert.match(orient, /^⚠ widget: 8 defects across 6 classes/m); + assert.match(orient, new RegExp(`unclassified in the 14 days from ${window.from} to ${window.to} 1 \\(${r3[1]}\\)`)); + const reported = convergence(root, { now: () => new Date() }); + assert.deepEqual(reported.deadEnds.deadEnds.map((d) => d.subsystem), ["widget"], "the convergence reading reads the same one"); + assert.deepEqual([reported.deadEnds.window.from, reported.deadEnds.window.to], [reported.window.from, reported.window.to], "over the convergence reading's own window"); + assert.match(convergenceText(reported), /^dead ends .*: 1; read the journals of 1 worktree;/m); + const short = convergence(root, { days: 1, now: () => new Date() }); + assert.deepEqual([short.deadEnds.window, short.deadEnds.deadEnds], [{ days: 1, from: short.window.from, to: short.window.to }, []], "--days narrows the dead ends' window too, and two days back lies outside one day"); + + // A human's answer about another component restarts nothing here. + const aside = idOf(j("escalate", "the gadget hums: retune it?", "--because", "one defect", "--cite", elsewhere, ...WHO)); + idOf(j("acknowledge", aside, "--human", "retune it", "--because", "the owner chose a retune", ...WHO)); + assert.deepEqual(readDeadEnds(root, model.components).deadEnds.map((d) => [d.subsystem, d.answered, d.escalation]), [["widget", undefined, undefined]]); + // Asked of a human: an escalation citing one of its defects waits, named in the line and above every read. + const asked = idOf(j("escalate", "widget is at a dead end: redesign it or keep guarding?", "--because", "its guards keep failing", "--cite", r3[2]!, ...WHO)); + const waiting = readDeadEnds(root, model.components).deadEnds[0]!; + assert.equal(waiting.escalation, asked); + assert.match(specBlock(root), new RegExp(`escalated as ${asked}, awaiting a human \\(acknowledge ${asked} --human`)); + assert.match(escalationBlock(root), new RegExp(`▲ ${asked}`)); + // An agent's acknowledgement carries no human's words: it restarts nothing, and the reading asks again. + idOf(j("acknowledge", asked, "--because", "keep guarding", ...WHO)); + const still = readDeadEnds(root, model.components).deadEnds; + assert.deepEqual(still.map((d) => [d.subsystem, d.escalation, d.answered]), [["widget", undefined, undefined]]); + assert.match(deadEndLine(still[0]!), /ask a human whether to redesign it: escalate/); + // A human's answer: the count starts again after it, so the dead end is gone until the subsystem fails again. + const again = idOf(j("escalate", "widget is still at a dead end: redesign it?", "--because", "an agent answered the first", "--cite", r3[2]!, ...WHO)); + idOf(j("acknowledge", again, "--human", "redesign the knob", "--because", "the owner chose a redesign", ...WHO)); + assert.deepEqual(readDeadEnds(root, model.components).deadEnds, []); + assert.doesNotMatch(specBlock(root), /Dead ends|read the journals/, "with no dead end, orient says nothing of the reading"); + // Outside the window it is no dead end either: the pure reading, a month on. + const records = loadJournal(root).records; + const later = deadEnds(records, defectStates(records), { folders: ["widget", "gadget"], holding: (f) => f.split("/")[0], root, standing: () => "witnessed", now: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) }); + assert.deepEqual(later, []); +}); + +test("converging work is no dead end: defects across classes, families and rounds whose arrivals fall round over round are not named, however they closed", () => { + const rules = Array.from({ length: 10 }, (_, i) => `rule ${i}`); + const spec = ["# Gear", "", "Gears mesh.", "", "## invariants", ...rules.flatMap((r) => [`- ${r}: The gear keeps ${r}.`, " over: every gear", ` via: the gear keeps ${r}`, " because: a gear that slips breaks", " kinds: none"]), ""].join("\n"); + const root = project({ "gear/Gear.spec.md": spec }); + commitAll(root, "first", RECENT); + for (const r of rules) witness(root, "gear", r, "2026-10-01T00:00:00.000Z"); + const j = journal(root, clock(RECENT)); + let fresh = 1; + const found = (what: string, cls: string | undefined, close: "old guard" | "new guard" | "open") => { + const id = idOf(j("defect", what, "--evidence", "seen", ...(cls === undefined ? [] : ["--class", cls]), "--file", "gear/teeth.ts", ...WHO)); + if (close !== "open") idOf(j("resolved", id, "--because", "a door", "--guard", `gear/${close === "old guard" ? rules[0] : rules[fresh++]}`, ...WHO)); + return id; + }; + found("a tooth slipped", "path-identity", "old guard"); + // Three rounds of three, three and two: the closes are every kind there is, and none of them decides it. + for (const [round, batch] of [ + [1, [["a gear list was kept by hand", "hand-list", "old guard"], ["a second gear list", "hand-list", "open"], ["a slow mesh", "cost", "new guard"]]], + [2, [["the manual named the wrong gear", "audience", "old guard"], ["the mesh claimed every tooth", "over-claim", "open"], ["a third gear list", undefined, "old guard"]]], + [3, [["a tooth read as two", "parse-gap", "open"], ["the guide omits the ratio", "audience", "old guard"]]], + ] as const) { + commitAll(root, `round ${round}`, RECENT); + for (const [what, cls, close] of batch) found(what, cls, close); + } + const model = loadSpecModel(root); + assert.deepEqual(readDeadEnds(root, model.components).deadEnds, [], "the arrivals fell"); + const out: string[] = []; + specCommand([root], { cwd: root, out: (l) => out.push(l), err: (l) => out.push(l) }); + assert.doesNotMatch(out.join("\n"), /DEAD END/); + assert.match(out.join("\n"), /^dead ends: 0; read the journals of 1 worktree;/m); + // spec --check says what it read and names the defect with no class; orient, with no dead end, says nothing of it. + assert.match(out.join("\n"), /^dead ends: 0; read the journals of 1 worktree; .*unclassified in the 14 days from \S+ to \S+ 1 \(df-[0-9a-f]{8}\)/m); + assert.doesNotMatch(specBlock(root), /Dead ends|read the journals/, "orient injects no total when nothing is at a dead end"); + // The other thresholds are crossed: it is the falling arrivals that tell converging work from a dead end. + const records = loadJournal(root).records; + const options = { folders: ["gear"], holding: (f: string) => (f.startsWith("gear/") ? "gear" : undefined), root, standing: () => "witnessed" as const, now: new Date() }; + const loose = deadEnds(records, defectStates(records), { ...options, thresholds: { rise: -Infinity } }); + assert.deepEqual(loose.map((d) => [d.subsystem, d.defects.length, d.classes.length, d.unclassified, d.rounds.map((r) => r.defects), d.trend]), [["gear", 8, 5, 1, [3, 3, 2], { earlier: 3, later: 2 }]]); + assert.ok(loose[0]!.classes.some((c) => c.name === "hand-list") && loose[0]!.classes.some((c) => c.name === "audience"), "families count as classes do"); +}); + +test("a defect names its component: --component, or the one component holding its files, and a reader derives one only for a record without it and says so", () => { + const root = project({ "gadget/Gadget.spec.md": SPEC.replace("# Widget", "# Gadget").replace("Widgets turn.", "Gadgets hum.") }); + const j = journal(root, clock(RECENT)); + const record = (id: string) => loadJournal(root).records.find((r) => r.id === id) as Defect; + const byFile = idOf(j("defect", "the knob slipped", "--evidence", "seen", "--file", "widget/knob.ts", "--file", "widget/deep/axle.ts", ...WHO)); + assert.equal(record(byFile).component, "widget", "every file in one component names it"); + const given = idOf(j("defect", "the hum drifted", "--evidence", "heard", "--component", "gadget/", ...WHO)); + assert.equal(record(given).component, "gadget", "--component names it outright"); + const split = j("defect", "two parts rattled", "--evidence", "shook", "--file", "widget/knob.ts", "--file", "gadget/hum.ts", ...WHO); + assert.equal(record(idOf(split)).component, undefined, "files in two components name neither"); + assert.match(split.out.join("\n"), /no component: its files lie in gadget and widget, so it counts toward each/); + // A defect that says nothing of where it lies is refused, and told what to pass: placed nowhere, it would count toward no dead end. + const bare = j("defect", "something rattled", "--evidence", "shook", ...WHO); + assert.equal(bare.code, 1); + assert.match(bare.err.join("\n"), /say where the fault lies, or the dead-end reading counts it nowhere: --file for each file of the fault \(repeatable\), or --component \(components: gadget, widget\); when no file or component of the project holds it, --unplaced ""/); + const nowhere = j("defect", "the host dropped a hook", "--evidence", "its log", "--unplaced", "the fault is the host's, in no file of this project", ...WHO); + assert.equal(record(idOf(nowhere)).unplaced, "the fault is the host's, in no file of this project", "--unplaced says why, and is written"); + assert.equal(record(idOf(nowhere)).component, undefined); + assert.match(nowhere.out.join("\n"), /unplaced: it counts toward no subsystem's dead end/); + assert.equal(j("defect", "both", "--evidence", "e", "--unplaced", "why", "--file", "widget/knob.ts", ...WHO).code, 1, "--unplaced and a file contradict each other"); + assert.equal(j("defect", "blank", "--evidence", "e", "--unplaced", " ", ...WHO).code, 1, "--unplaced needs its why"); + const refused = j("defect", "a ghost rattled", "--evidence", "shook", "--component", "nowhere", ...WHO); + assert.equal(refused.code, 1); + assert.match(refused.err.join("\n"), /--component nowhere names no component \(a folder holding a spec\); components: gadget, widget/); + // A component that does not own every file the defect names is refused: the files decide where it counts, never the flag. + const before = loadJournal(root).records.length; + const moved = j("defect", "the knob slipped again", "--evidence", "seen", "--component", "gadget", "--file", "widget/knob.ts", ...WHO); + assert.equal(moved.code, 1); + assert.match(moved.err.join("\n"), /--component gadget does not own every file the defect names: widget\/knob\.ts \(in widget\)/); + const narrowed = j("defect", "two parts rattled again", "--evidence", "shook", "--component", "widget", "--file", "widget/knob.ts", "--file", "gadget/hum.ts", ...WHO); + assert.equal(narrowed.code, 1, "a defect of two components cannot be narrowed to one"); + assert.match(narrowed.err.join("\n"), /gadget\/hum\.ts \(in gadget\)/); + const loose = j("defect", "the knob and the notes", "--evidence", "read", "--component", "widget", "--file", "widget/knob.ts", "--file", "NOTES.md", ...WHO); + assert.equal(loose.code, 1, "a file in no component is owned by none"); + assert.match(loose.err.join("\n"), /NOTES\.md \(in no component\)/); + // A path is read with its ".." resolved before its owner is decided: gadget/../widget/knob.ts is widget's. + const dotted = j("defect", "the knob slipped by a dotted path", "--evidence", "seen", "--file", "gadget/../widget/knob.ts", "--component", "gadget", ...WHO); + assert.equal(dotted.code, 1, "a .. segment does not let gadget own widget's file"); + assert.match(dotted.err.join("\n"), /gadget\/\.\.\/widget\/knob\.ts \(in widget\)/); + assert.equal(loadJournal(root).records.length, before, "nothing was written"); + assert.equal(record(idOf(j("defect", "the knob slipped by a dotted path", "--evidence", "seen", "--file", "./gadget/../widget/knob.ts", ...WHO))).component, "widget", "without --component the dotted path names widget"); + assert.equal(record(idOf(j("defect", "the axle bent", "--evidence", "seen", "--component", "widget", "--file", "widget/deep/axle.ts", ...WHO))).component, "widget", "a component that owns every file is written"); + // Without --component a file outside every component, or outside the project, leaves the record with none: the one component must own every file. + const outside = j("defect", "the knob and the notes", "--evidence", "read", "--file", "widget/knob.ts", "--file", "NOTES.md", ...WHO); + assert.equal(record(idOf(outside)).component, undefined); + assert.match(outside.out.join("\n"), /no component: NOTES\.md lies in no component/); + assert.equal(record(idOf(j("defect", "the knob and a sibling", "--evidence", "read", "--file", "widget/knob.ts", "--file", "../elsewhere/x.ts", ...WHO))).component, undefined); + // A record written before the field: the store is append-only, so it is read as written and placed by derivation, and counted as derived. + const oldDefect = (id: string, files: string[]) => ({ id, kind: "defect", at: RECENT, session: "old", agent: "old", commit: null, dirty: false, what: "an old slip", evidence: "e", files }); + const old = oldDefect("df-01d01d00", ["widget/knob.ts"]); + const olds = [old, oldDefect("df-01d01d01", []), oldDefect("df-01d01d02", ["gadget/../widget/knob.ts"]), oldDefect("df-01d01d03", ["widget/knob.ts"]), oldDefect("df-01d01d04", ["NOTES.md"])]; + writeFileSync(join(root, ".coherence", "journal", "old.jsonl"), olds.map((r) => JSON.stringify(r)).join("\n") + "\n"); + // Closed under a guard: one that names no file is placed by it; one whose file names widget stays widget's, whatever component its guard is declared in. + idOf(j("resolved", "df-01d01d01", "--because", "a check", "--guard", "widget/knob turns", ...WHO)); + idOf(j("resolved", "df-01d01d03", "--because", "a check", "--guard", "gadget/knob turns", ...WHO)); + const model = loadSpecModel(root); + const reading = readDeadEnds(root, model.components); + assert.deepEqual(reading.placement, { recorded: 4, files: 6, guard: 1, unplaced: 2 }, "four named; the split, the two with a file in no or outside a component and three old ones derived from their files; one old one from its guard; the --unplaced one and the old one in no component unplaced"); + const placed = new Map(defectStates(loadJournal(root).records).map((st) => [st.id, placeDefect(st, { folders: ["widget", "gadget"], holding: (f) => componentHolding(model.components, f)?.folder, root })])); + assert.deepEqual(placed.get("df-01d01d01"), { subsystems: ["widget"], by: "guard" }, "no file: its guard"); + assert.deepEqual(placed.get("df-01d01d02"), { subsystems: ["widget"], by: "files" }, "the dotted path is widget's"); + assert.deepEqual(placed.get("df-01d01d03"), { subsystems: ["widget"], by: "files" }, "its files, else its guard: gadget's guard adds nothing to a defect whose file is widget's"); + assert.deepEqual(placed.get("df-01d01d04"), { subsystems: [], by: "unplaced" }); + assert.equal(loadJournal(root).records.find((r) => r.id === old.id)!.kind, "defect", "the old record is read as written"); +}); + +test("the journal is read from every worktree of the repository, each record once, and a defect recorded only in another worktree reaches the dead-end reading", () => { + const root = project(); + commitAll(root, "first", RECENT); + const j = journal(root, clock(RECENT)); + const shared = idOf(j("decide", "a choice both checkouts hold", "--over", "none", "--because", "committed before the second worktree", ...WHO)); + execFileSync("git", ["add", "-f", ".coherence"], { cwd: root }); + commitAll(root, "the shared record", RECENT); + const worktree = (): string => { + const folder = made(mkdtempSync(join(tmpdir(), "coherence-worktree-"))); + rmSync(folder, { recursive: true }); + execFileSync("git", ["worktree", "add", "-q", "--detach", folder], { cwd: root }); + return folder; + }; + const other = worktree(); + const elsewhere = idOf(journal(other, clock(RECENT))("defect", "the knob slipped in the other checkout", "--evidence", "seen", "--file", "widget/knob.ts", ...WHO)); + // A legacy store file of one name and one size in both checkouts, holding different records: neither stands for the other. + const legacy = (id: string, chose: string) => JSON.stringify({ id, kind: "decision", at: RECENT, session: "legacy", agent: "a", commit: null, dirty: false, chose, over: [], because: "b" }) + "\n"; + writeFileSync(join(root, ".coherence", "journal", "legacy.jsonl"), legacy("d-aaaaaaaa", "made in the reading checkout")); + writeFileSync(join(other, ".coherence", "journal", "legacy.jsonl"), legacy("d-bbbbbbbb", "made in the second checkout!")); + assert.equal(readFileSync(join(root, ".coherence", "journal", "legacy.jsonl")).length, readFileSync(join(other, ".coherence", "journal", "legacy.jsonl")).length); + // A store file that cannot be read in one worktree hides nothing of the same name in another, and is said. + const third = worktree(); + mkdirSync(join(third, ".coherence", "journal", "stuck.jsonl"), { recursive: true }); + mkdirSync(join(other, ".coherence", "journal"), { recursive: true }); + writeFileSync(join(other, ".coherence", "journal", "stuck.jsonl"), legacy("d-cccccccc", "beside an unreadable twin")); + // A worktree git calls prunable, its folder still there with a journal in it, and one whose folder is gone: neither is read. + const prunable = worktree(); + mkdirSync(join(prunable, ".coherence", "journal"), { recursive: true }); + writeFileSync(join(prunable, ".coherence", "journal", "p.jsonl"), legacy("d-dddddddd", "in a prunable worktree")); + rmSync(join(prunable, ".git")); + const missing = worktree(); + execFileSync("git", ["worktree", "lock", missing], { cwd: root }); + rmSync(missing, { recursive: true }); + + const snapshot = (folder: string): string => readdirSync(join(folder, ".coherence", "journal"), { recursive: true }).map(String).sort().map((name) => { + try { + return `${name}:${readFileSync(join(folder, ".coherence", "journal", name), "utf8")}`; + } catch { + return name; + } + }).join("\n"); + const before = [root, other, third].map(snapshot); + const own = loadJournal(root).records.map((r) => r.id); + assert.ok(own.includes(shared) && !own.includes(elsewhere), "a checkout's own journal holds only its own records"); + const across = loadJournalAcrossWorktrees(root); + const ids = across.records.map((r) => r.id); + assert.equal(ids.filter((id) => id === shared).length, 1, "the committed record both worktrees hold is read once"); + assert.ok(ids.includes(elsewhere), "the other worktree's record is read"); + assert.ok(ids.includes("d-aaaaaaaa") && ids.includes("d-bbbbbbbb"), "two files of one name and size with different records are both read"); + assert.ok(ids.includes("d-cccccccc"), "a file is not hidden by an unreadable one of its name elsewhere"); + assert.ok(across.damaged.some((d) => d.file === join(realpathSync(third), ".coherence", "journal", "stuck.jsonl") && d.line === 0 && /not read/.test(d.reason)), `the unreadable file is said: ${JSON.stringify(across.damaged)}`); + assert.ok(!ids.includes("d-dddddddd"), "a prunable worktree is not read"); + assert.deepEqual(across.worktrees[0], { path: root, self: true, records: own.length, only: own.length }); + const read = new Map(across.worktrees.slice(1).map((w) => [realpathSync(w.path), w.only])); + assert.deepEqual(read, new Map([[realpathSync(other), 3], [realpathSync(third), 0]]), "the other two live worktrees, the prunable and the missing one left out"); + assert.deepEqual([root, other, third].map(snapshot), before, "nothing is written into any worktree it reads, the others' included"); + const reading = readDeadEnds(root, loadSpecModel(root).components); + assert.equal(reading.worktrees.length, 3); + assert.equal(reading.placement.recorded, 1, "the other worktree's defect is placed by the component its record names"); + const out: string[] = []; + specCommand([root], { cwd: root, out: (l) => out.push(l), err: (l) => out.push(l) }); + assert.match(out.join("\n"), /^dead ends: 0; read the journals of 3 worktrees, records only in .*coherence-worktree-[^ ]+ \(3\), 1 unreadable line or file;/m); + // Orient, with no dead end, injects nothing of the reading. + assert.doesNotMatch(specBlock(root), /Dead ends|read the journals/); + + // What the reading parsed is kept in the user's cache, never in a worktree, filed by each file's identity: an append to another worktree's file is read at once, and an index that will not parse is read as none. + const indexes = join(process.env["XDG_CACHE_HOME"]!, "coherence", "journal-index"); + assert.ok(readdirSync(indexes).some((n) => n.endsWith(".json")), "the index is in the user's cache"); + const otherFile = join(other, ".coherence", "journal", readdirSync(join(other, ".coherence", "journal")).find((n) => n !== "legacy.jsonl" && n !== "stuck.jsonl")!); + appendFileSync(otherFile, legacy("d-ffffffff", "appended after the last reading")); + assert.ok(loadJournalAcrossWorktrees(root).records.some((r) => r.id === "d-ffffffff"), "a file whose identity changed is read again"); + for (const name of readdirSync(indexes)) writeFileSync(join(indexes, name), "{ not an index"); + assert.deepEqual(new Set(loadJournalAcrossWorktrees(root).records.map((r) => r.id)), new Set([...ids, "d-ffffffff"]), "an index that will not parse is read as none"); + + // The remedy the reading prints works from the checkout it speaks in, whichever worktree holds the record it names. + const here = journal(root, clock(RECENT)); + const there = journal(other, clock(RECENT)); + const cited = here("escalate", "widget is at a dead end: redesign it or keep guarding?", "--because", "its defect lies in another checkout", "--cite", elsewhere, ...WHO); + idOf(cited); + assert.match(cited.out.join("\n"), new RegExp(`cites ${elsewhere} \\(in another worktree's journal, not in this checkout\\)`)); + idOf(here("classify", elsewhere, "--class", "path-identity", "--because", "the knob's path", ...WHO)); + const asked = idOf(there("escalate", "widget again: redesign it?", "--because", "asked in the other checkout", "--cite", elsewhere, ...WHO)); + idOf(here("acknowledge", asked, "--human", "redesign it", "--because", "the owner chose a redesign", ...WHO)); + const answeredThere = idOf(there("escalate", "widget a third time?", "--because", "asked and answered there", "--cite", elsewhere, ...WHO)); + idOf(there("acknowledge", answeredThere, "--human", "keep it", "--because", "the owner kept it", ...WHO)); + const twice = here("acknowledge", answeredThere, "--human", "keep it", "--because", "answered again", ...WHO); + assert.equal(twice.code, 1, "an answer in another worktree answers the escalation here too"); + assert.match(twice.err.join("\n"), new RegExp(`${answeredThere} was already answered`)); + + // A store file of the checkout's own that cannot be read is reported as damaged by the reading, never thrown; a verb that answers a record refuses, since the file may hold the answer. + mkdirSync(join(root, ".coherence", "journal", "stuck.jsonl")); + const refusedWrite = here("classify", elsewhere, "--class", "cost", "--because", "a second look", ...WHO); + assert.equal(refusedWrite.code, 1); + assert.match(refusedWrite.err.join("\n"), /the journal cannot be read: \.coherence\/journal\/stuck\.jsonl not read/); + assert.ok(loadJournalAcrossWorktrees(root).damaged.some((d) => d.file === join(".coherence", "journal", "stuck.jsonl") && d.line === 0 && /not read/.test(d.reason))); + const damagedOut: string[] = []; + specCommand([root], { cwd: root, out: (l) => damagedOut.push(l), err: (l) => damagedOut.push(l) }); + assert.match(damagedOut.join("\n"), /^dead ends: 0; read the journals of 3 worktrees, .*2 unreadable lines or files;/m); + assert.equal(typeof specBlock(root), "string", "orient reads on"); + rmSync(join(root, ".coherence", "journal", "stuck.jsonl"), { recursive: true }); + execFileSync("git", ["worktree", "unlock", missing], { cwd: root }); + for (const folder of [other, third]) execFileSync("git", ["worktree", "remove", "--force", folder], { cwd: root }); + execFileSync("git", ["worktree", "prune"], { cwd: root }); + + // A bare repository's own entry is no worktree to read, even with a journal folder inside it. + const bare = made(mkdtempSync(join(tmpdir(), "coherence-bare-"))); + execFileSync("git", ["clone", "-q", "--bare", root, join(bare, "repo.git")]); + mkdirSync(join(bare, "repo.git", ".coherence", "journal"), { recursive: true }); + writeFileSync(join(bare, "repo.git", ".coherence", "journal", "b.jsonl"), legacy("d-eeeeeeee", "inside the bare repository")); + execFileSync("git", ["worktree", "add", "-q", "--detach", join(bare, "checkout")], { cwd: join(bare, "repo.git") }); + const fromBare = loadJournalAcrossWorktrees(join(bare, "checkout")); + assert.deepEqual(fromBare.worktrees.map((w) => w.self), [true], "the bare entry is left out"); + assert.ok(!fromBare.records.some((r) => r.id === "d-eeeeeeee")); + + // A project nested inside its repository: each other worktree is read at the project's own folder in it, never at that worktree's top. + const repo = made(mkdtempSync(join(tmpdir(), "coherence-nested-"))); + mkdirSync(join(repo, "app"), { recursive: true }); + writeFileSync(join(repo, "app", "App.spec.md"), SPEC.replace("# Widget", "# App")); + execFileSync("git", ["init", "-q"], { cwd: repo }); + commitAll(repo, "first", RECENT); + const nested = made(mkdtempSync(join(tmpdir(), "coherence-nested-worktree-"))); + rmSync(nested, { recursive: true }); + execFileSync("git", ["worktree", "add", "-q", "--detach", nested], { cwd: repo }); + for (const [folder, id] of [[join(nested, "app"), "d-a0000001"], [nested, "d-a0000002"]] as const) { + mkdirSync(join(folder, ".coherence", "journal"), { recursive: true }); + writeFileSync(join(folder, ".coherence", "journal", "n.jsonl"), legacy(id, "made in the nested worktree")); + } + const fromNested = loadJournalAcrossWorktrees(join(repo, "app")); + assert.deepEqual(fromNested.worktrees.map((w) => realpathSync(w.path)), [realpathSync(join(repo, "app")), realpathSync(join(nested, "app"))]); + assert.deepEqual(fromNested.records.map((r) => r.id), ["d-a0000001"], "the project's folder in the other worktree is read, and that worktree's top is not"); + execFileSync("git", ["worktree", "remove", "--force", nested], { cwd: repo }); +}); diff --git a/src/journal/defects.ts b/src/journal/defects.ts index 6597a359..f5156aa5 100644 --- a/src/journal/defects.ts +++ b/src/journal/defects.ts @@ -136,6 +136,12 @@ export interface DefectState { class?: string; introduced?: string; caught?: Caught; + /** The files the defect names, as it was recorded; empty when it named none. */ + files?: string[]; + /** The component the defect record names, when it was written with one; a record older than the field names none. */ + component?: string; + /** The short commit HEAD named when the defect was written, null where no git answered. */ + commit?: string | null; /** The resolution that closed it, unretracted; absent while it is open. */ resolution?: Resolution; } @@ -151,15 +157,20 @@ function fold(into: DefectOrigin, from: DefectOrigin): void { if (from.caught !== undefined) into.caught = from.caught; } -/** Every defect in the journal, oldest first, with its class, origin and catch folded and its close, if any. */ +/** + * Every defect in the journal, oldest first, with its class, origin and catch + * folded and its close, if any. A retracted defect is none: a withdrawn + * report is no fault, so no floor, convergence count or dead end reads it. + */ export function defectStates(records: readonly JournalRecord[]): DefectState[] { const gone = retracted(records); const ordered = [...records].sort((a, b) => (a.at < b.at ? -1 : a.at > b.at ? 1 : 0)); const states = new Map(); for (const record of ordered) { - if (record.kind === "defect") { + if (record.kind === "defect" && !gone.has(record.id)) { const d = record as Defect; - const state: DefectState = { id: d.id, at: d.at, what: d.what }; + const state: DefectState = { id: d.id, at: d.at, what: d.what, files: Array.isArray(d.files) ? d.files : [], commit: d.commit ?? null }; + if (typeof d.component === "string") state.component = d.component; fold(state, d); states.set(d.id, state); } else if (gone.has(record.id)) { diff --git a/src/journal/journal.test.ts b/src/journal/journal.test.ts index eb8498c1..67927362 100644 --- a/src/journal/journal.test.ts +++ b/src/journal/journal.test.ts @@ -459,7 +459,7 @@ test("a write binds to the one active order its session owns; none or several bi for (const verb of [ ["conjecture", "o", "--discriminated-by", "t"], ["unable", "w", "--because", "b"], - ["defect", "d", "--evidence", "e"], + ["defect", "d", "--evidence", "e", "--file", "src/a.ts"], ["escalate", "e", "--because", "b"], ["experiment", "create", "x", "--action", "a", "--success", "c"], ]) { @@ -517,7 +517,7 @@ test("citations resolve at the write: an unknown id refuses the write, a record assert.deepEqual((byId(cwd, decided) as { cites?: string[] }).cites, ["d-0ld00001", conjectured, order, move], "a decision cites a journal record of any kind, a work order, and a work order's move"); for (const [verb, ...args] of [ ["escalate", "a human must see", "--because", "b"], - ["defect", "it broke", "--evidence", "e"], + ["defect", "it broke", "--evidence", "e", "--file", "src/a.ts"], ["conjecture", "maybe", "--discriminated-by", "t"], ["unable", "could not", "--because", "wall"], ["experiment", "create", "it works", "--action", "try", "--success", "green"], @@ -597,7 +597,7 @@ test("--human records the words an agent attributes to a human, apart from its b const acked = idOf(run("acknowledge", escalated, "--because", "kept", "--human", "keep it", ...WHO)); assert.equal((byId(cwd, acked) as { human?: string }).human, "keep it"); assert.equal(run("decide", "blank", "--because", "b", "--human", " ", ...WHO).code, 1, "blank human words are refused"); - assert.equal(run("defect", "no human here", "--evidence", "e", "--human", "x", ...WHO).code, 1, "a verb that does not carry human words refuses the flag"); + assert.equal(run("defect", "no human here", "--evidence", "e", "--file", "src/a.ts", "--human", "x", ...WHO).code, 1, "a verb that does not carry human words refuses the flag"); const timeline = run("journal").out.join("\n"); assert.match(timeline, /because: the owner ruled it\n human \(as the agent attributes\): call it lexicon, but not yet/, "the timeline labels the words as the agent's attribution"); } finally { @@ -731,7 +731,7 @@ test("a record committed on another branch may be cited and read, and says where const typo = run("decide", "x", "--because", "b", "--cite", "d-00000000", "--session", "main-1", "--agent", "main"); assert.equal(typo.code, 1); - assert.match(typo.err.join("\n"), /--cite d-00000000: no journal or work record has that id, here or committed on another branch/); + assert.match(typo.err.join("\n"), /--cite d-00000000: no journal or work record has that id, in any worktree or committed on another branch/); } finally { rmSync(root, { recursive: true, force: true }); } diff --git a/src/journal/record.ts b/src/journal/record.ts index e3443059..1f7ab038 100644 --- a/src/journal/record.ts +++ b/src/journal/record.ts @@ -180,6 +180,20 @@ export interface Defect extends Head, Citing, DefectOrigin { what: string; evidence: string; files: string[]; + /** + * The component the defect belongs to, as its folder: given with + * --component, or derived at the write as the one component whose folder + * holds every file it names. Absent on a record written before the field, + * or whose files name no single component; readers derive one then, and + * say they did. + */ + component?: string; + /** + * Why no file or component of the project holds the fault, given with + * --unplaced in place of --file and --component: the defect counts toward + * no subsystem, and says why. + */ + unplaced?: string; } /** One planned action or one observable criterion, with the id its result binds to. */ @@ -489,7 +503,7 @@ export const RECORD_ROLES: { readonly [K in AnyRecord["kind"]]: FieldRoles { + try { + return realpathSync(path); + } catch { + return path; + } + }; + const self = real(top); + const out: string[] = []; + let main: string | undefined; + for (const block of listed.split(/\n\s*\n/)) { + const lines = block.split("\n"); + const path = lines.find((l) => l.startsWith("worktree "))?.slice("worktree ".length); + if (path === undefined) continue; + main ??= real(path); + if (lines.some((l) => l === "bare" || l.startsWith("prunable"))) continue; + if (real(path) === self || !existsSync(path)) continue; + out.push(join(path, prefix)); + } + return main === undefined ? { others: out } : { main: join(main, prefix), others: out }; +} + +/** The bytes of each store file in a journal folder, by name; one that cannot be read is said, never taken as a file with no records. */ +function storeFiles(dir: string, damaged: Damaged[], shown: string): Map { + const out = new Map(); + for (const name of storeNames(dir, damaged, shown)) { + try { + out.set(name, readFileSync(join(dir, name))); + } catch (error) { + damaged.push({ file: join(shown, name), line: 0, reason: `not read: ${error instanceof Error ? error.message : String(error)}` }); + } + } + return out; +} + +/** The store files' names in a journal folder, sorted; no folder is a worktree with no records, and any other refusal is said. */ +function storeNames(dir: string, damaged: Damaged[], shown: string): string[] { + try { + return readdirSync(dir).filter(isStoreFile).sort(); + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== "ENOENT") damaged.push({ file: shown, line: 0, reason: `not read: ${error instanceof Error ? error.message : String(error)}` }); + return []; + } +} + +/** A store file's lines, each with its key and what it parses to: the whole file, every line once, whatever other files hold. */ +function parsedLines(text: string): { lines: IndexedLine[]; parsed: Map } { + const lines: IndexedLine[] = []; + const parsed = new Map(); + for (const { line, number } of storeLines(text, new Set())) { + const key = lineKey(line.trim()); + lines.push([key, number]); + if (!parsed.has(key)) parsed.set(key, parseLine(line)); + } + return { lines, parsed }; +} + +/** + * The journal of every worktree of the repository in one timeline, each + * record once: an agent records its defects in the checkout it works in, so + * a reading of one checkout alone misses the worktree where the work went + * wrong. The self is read as loadJournal reads it, except that a store file + * it cannot read is reported as damaged rather than thrown; every store file + * of each other worktree is read, and one whose bytes equal a file already + * read (their digests agree) is the same records and is not parsed again, + * whatever its name; a record whose text or id was already read is the same + * record. Nothing is skipped by a file's name or size, so two worktrees' + * files of one name and size with different records are both read, and a + * file that cannot be read is reported as damaged, never taken to stand for + * another. Read only, never written: what was parsed is kept in the user's + * cache (worktree-index.ts), filed by each file's identity, so a file + * unchanged since the last reading is not read again. A line that will not + * parse in another worktree is reported with that worktree's path. + */ +export function loadJournalAcrossWorktrees(cwd: string): LoadedAcross { + const loaded: LoadedAcross = { records: [], damaged: [], worktrees: [] }; + // The self, read whole each time: its bytes are the truth the others are compared with. + const digests = new Set(); + const ownSeen = new Set(); + for (const [name, bytes] of storeFiles(journalDir(cwd), loaded.damaged, JOURNAL_DIR)) { + digests.add(digestOf(bytes)); + for (const { line, number } of storeLines(bytes.toString("utf8"), ownSeen)) { + const verdict = parseLine(line); + if (typeof verdict === "string") loaded.damaged.push({ file: join(JOURNAL_DIR, name), line: number, reason: verdict }); + else loaded.records.push(verdict); + } + } + const ids = new Set(loaded.records.map((r) => r.id)); + loaded.worktrees.push({ path: cwd, self: true, records: loaded.records.length, only: loaded.records.length }); + const { main, others } = worktreesOf(cwd); + if (others.length === 0) { + loaded.records.sort(compareRecords); + return loaded; + } + const index = WorktreeIndex.open(main); + const seen = new Set(); + for (const folder of others) { + const dir = journalDir(folder); + const worktree: WorktreeRead = { path: folder, self: false, records: 0, only: 0 }; + for (const name of storeNames(dir, loaded.damaged, dir)) { + const file = join(dir, name); + let content: { digest: string; lines: IndexedLine[] } | undefined; + try { + const s = statSync(file); + const identity = identityOf(s); + content = s.isFile() ? index.known(dir, name, identity) : undefined; + if (content === undefined) { + const bytes = readFileSync(file); + const digest = digestOf(bytes); + const { lines, parsed } = parsedLines(bytes.toString("utf8")); + index.record(dir, name, identity, digest, lines, parsed); + content = { digest, lines }; + } + } catch (error) { + loaded.damaged.push({ file, line: 0, reason: `not read: ${error instanceof Error ? error.message : String(error)}` }); + continue; + } + if (digests.has(content.digest)) continue; + digests.add(content.digest); + for (const [key, number] of content.lines) { + if (seen.has(key)) continue; + seen.add(key); + const verdict = index.line(key)!; + if (typeof verdict === "string") { + loaded.damaged.push({ file, line: number, reason: verdict }); + continue; + } + worktree.records += 1; + if (ids.has(verdict.id)) continue; + ids.add(verdict.id); + worktree.only += 1; + loaded.records.push(verdict); + } + } + loaded.worktrees.push(worktree); + } + index.save(); + loaded.records.sort(compareRecords); + return loaded; +} + /** A record, or the reason the line is not one. */ function parseLine(line: string): JournalRecord | string { let value: unknown; diff --git a/src/journal/verbs.ts b/src/journal/verbs.ts index 19f6a9bc..7e082574 100644 --- a/src/journal/verbs.ts +++ b/src/journal/verbs.ts @@ -16,6 +16,7 @@ * attributes to a human, stored apart from its own because. */ +import { isAbsolute } from "node:path"; import { JournalError, onePositional, parseFlags, required, type FlagShape, type Parsed } from "./args.ts"; import { INSTRUMENT_IS_WRONG, @@ -48,10 +49,10 @@ import { alternation, spoken, } from "./record.ts"; -import { loadSpecModel, projectPractices } from "../spec/model.ts"; +import { componentFolders, componentHolding, loadSpecModel, projectFile, projectPractices } from "../spec/model.ts"; import { originFields } from "./defects.ts"; import { amendCommand, floorGaps, type ModelPractice } from "../spec/practices.ts"; -import { appendRecordTo, gitState, loadJournal, type Loaded } from "./store.ts"; +import { appendRecordTo, gitState, loadJournal, loadJournalAcrossWorktrees, type Loaded } from "./store.ts"; import { describeBinding, loadWork } from "./work.ts"; import { recordsOnOtherBranches } from "./branches.ts"; import { recordDefectTelemetry } from "../lifecycle/telemetry.ts"; @@ -108,9 +109,11 @@ export const CITE: Record = { cite: "many" }; /** * The records a write cites, checked against both stores: each --cite must - * name a record already in the journal or the work store, of any kind, or - * one another branch has committed (a parallel session's, before it merges), - * and none may be given twice. An id found nowhere is refused: that is a typo. Returns the field to spread into the record, + * name a record already in the journal of any worktree of the repository + * (the journals the dead-end reading reads, so an id it names can be cited + * from any checkout) or in the work store, of any kind, or one another + * branch has committed (a parallel session's, before it merges), and none + * may be given twice. An id found nowhere is refused: that is a typo. Returns the field to spread into the record, * empty when nothing is cited, so a record that cites nothing looks exactly * like one written before citations existed. This is the one site that * accepts a citation. @@ -119,7 +122,7 @@ export function citations(parsed: Parsed, cwd: string): { cites?: string[] } { const given = parsed.many.get("cite") ?? []; if (given.length === 0) return {}; const known = new Set([ - ...loadJournal(cwd).records.map((record) => record.id), + ...answerable(cwd).records.map((record) => record.id), ...loadWork(cwd).records.map((record) => record.id), ]); const seen = new Set(); @@ -131,20 +134,37 @@ export function citations(parsed: Parsed, cwd: string): { cites?: string[] } { const unknown = given.filter((id) => !known.has(id)); const elsewhere = unknown.length === 0 ? new Map() : recordsOnOtherBranches(cwd, unknown); const missing = unknown.find((id) => !elsewhere.has(id)); - if (missing !== undefined) throw new JournalError(`--cite ${missing}: no journal or work record has that id, here or committed on another branch; cite a record that exists (journal, work inspect)`); + if (missing !== undefined) throw new JournalError(`--cite ${missing}: no journal or work record has that id, in any worktree or committed on another branch; cite a record that exists (journal, work inspect)`); return { cites: given }; } -/** Each cited id, with the branch that holds it when this checkout does not. */ +/** Each cited id, with where it lies when this checkout does not hold it: another worktree's journal, or another branch. */ function citedWhere(cwd: string, ids: readonly string[]): string[] { const local = new Set([...loadJournal(cwd).records.map((r) => r.id), ...loadWork(cwd).records.map((r) => r.id)]); - const elsewhere = recordsOnOtherBranches(cwd, ids.filter((id) => !local.has(id))); + const away = ids.filter((id) => !local.has(id)); + const worktrees = new Set(away.length === 0 ? [] : answerable(cwd).records.map((r) => r.id)); + const elsewhere = recordsOnOtherBranches(cwd, away.filter((id) => !worktrees.has(id))); return ids.map((id) => { + if (worktrees.has(id)) return `${id} (in another worktree's journal, not in this checkout)`; const found = elsewhere.get(id); return found === undefined ? id : `${id} (on branch ${found.branch}, not in this checkout)`; }); } +/** + * The journal a verb that answers or cites an earlier record looks in: every + * worktree's, the self's included, which is what the dead-end reading reads; + * an id that reading names, and a remedy it prints, works from any checkout. + * A store file of this checkout's own that cannot be read refuses the write, + * as loadJournal does: it may hold the answer the verb would duplicate. + */ +function answerable(cwd: string): Loaded { + const loaded = loadJournalAcrossWorktrees(cwd); + const unread = loaded.damaged.find((d) => d.line === 0 && !isAbsolute(d.file)); + if (unread !== undefined) throw new JournalError(`the journal cannot be read: ${unread.file} ${unread.reason}`); + return loaded; +} + /** The words a human said, as the agent attributes them; refused when given blank. */ function humanWords(parsed: Parsed): { human?: string } { const human = parsed.one.get("human"); @@ -170,7 +190,7 @@ function write(ctx: Context, record: JournalRecord, extra: string[] = []): Writt /** The record an id names, refused when absent or of another kind. */ function target(loaded: Loaded, id: string, kind: K | null, verb: string): JournalRecord & { kind: K } { const found = loaded.records.find((record) => record.id === id); - if (found === undefined) throw new JournalError(`${verb}: no record with id ${id}`); + if (found === undefined) throw new JournalError(`${verb}: no record with id ${id} in the journal of any worktree`); if (kind !== null && found.kind !== kind) { throw new JournalError(`${verb}: ${id} is a ${found.kind}, not a ${kind}`); } @@ -215,7 +235,7 @@ export function retract(argv: string[], ctx: Context): Written { const who = attribution(parsed); const of = onePositional(parsed, "the id to retract"); const because = required(parsed, "because", "a retraction records what refuted the record"); - const loaded = loadJournal(ctx.cwd); + const loaded = answerable(ctx.cwd); const found = target(loaded, of, null, "retract"); if (found.kind === "retraction") throw new JournalError(`retract: ${of} is itself a retraction`); refuseIfAnswered(loaded, of, "retract", ["retraction"]); @@ -260,7 +280,7 @@ export function resolved(argv: string[], ctx: Context): Written { const who = attribution(parsed); const of = onePositional(parsed, "the conjecture or defect id"); const because = required(parsed, "because", "a resolution records what the test showed, or what fixed the defect"); - const loaded = loadJournal(ctx.cwd); + const loaded = answerable(ctx.cwd); const found = target(loaded, of, null, "resolved"); if (found.kind !== "conjecture" && found.kind !== "defect") throw new JournalError(`resolved: ${of} is a ${found.kind}, not a conjecture or a defect`); refuseIfAnswered(loaded, of, "resolved", ["resolution", "dismissal"]); @@ -322,8 +342,7 @@ export function classify(argv: string[], ctx: Context): Written { const who = attribution(parsed); const of = onePositional(parsed, "the defect id"); const because = required(parsed, "because", "a classification records the evidence it rests on"); - const loaded = loadJournal(ctx.cwd); - target(loaded, of, "defect", "classify"); + target(answerable(ctx.cwd), of, "defect", "classify"); const fields = originFields(originGiven(parsed), ctx.cwd); if (Object.keys(fields).length === 0) throw new JournalError("classify: give at least one of --class, --introduced, --caught"); const said = [fields.class === undefined ? "" : `class ${fields.class}`, fields.introduced === undefined ? "" : `introduced ${fields.introduced}`, fields.caught === undefined ? "" : `caught ${fields.caught}`].filter((s) => s !== ""); @@ -339,21 +358,93 @@ export function dismiss(argv: string[], ctx: Context): Written { const who = attribution(parsed); const of = onePositional(parsed, "the conjecture id"); const because = required(parsed, "because", "a dismissal records why nobody will chase the conjecture"); - const loaded = loadJournal(ctx.cwd); + const loaded = answerable(ctx.cwd); target(loaded, of, "conjecture", "dismiss"); refuseIfAnswered(loaded, of, "dismiss", ["resolution", "dismissal"]); const record: Dismissal = { ...head("dismissal", who, ctx, `${of}\n${because}`), of, because }; return write(ctx, record); } +/** + * The component a defect belongs to, settled at the write. A file's owner is + * the deepest component folder above it, decided on the path with every "." + * and ".." resolved (projectFile); a file outside the project or outside + * every component has none. Without --component the record carries the one + * component that owns every file the defect names, and none when the files + * have several owners or when one has none, with a line saying why. + * --component is refused unless it names a component folder that owns every + * file the defect names: a defect's own files decide where it counts, so + * naming another component cannot move it out of the dead-end reading of the + * one that holds the fault. A defect whose files lie in several components + * takes no --component and counts toward each. + */ +function defectComponent(given: string | undefined, files: readonly string[], cwd: string): { component?: string; note?: string } { + const folders = componentFolders(cwd); + const owners = files.map((named) => { + const file = projectFile(cwd, named); + return { named, owner: file === undefined ? undefined : componentHolding(folders.map((f) => ({ folder: f })), file)?.folder }; + }); + const loose = owners.filter((o) => o.owner === undefined).map((o) => o.named); + const held = new Set(owners.flatMap((o) => (o.owner === undefined ? [] : [o.owner]))); + if (given !== undefined) { + const folder = given.trim().replace(/^\.\/(?=.)/, "").replace(/\/+$/, "") || "."; + if (!folders.includes(folder)) throw new JournalError(`--component ${given} names no component (a folder holding a spec); components: ${folders.join(", ") || "none"}`); + const elsewhere = owners.filter((o) => o.owner !== folder).map((o) => `${o.named} (${o.owner === undefined ? "in no component" : `in ${o.owner}`})`); + if (elsewhere.length > 0) { + throw new JournalError( + `--component ${folder} does not own every file the defect names: ${elsewhere.join(", ")}; a defect counts where its files lie, so leave --component off (a defect whose files lie in several components counts toward each), or name only the files of the fault`, + ); + } + return { component: folder }; + } + if (loose.length === 0 && held.size === 1) return { component: [...held][0]! }; + const how = "the dead-end reading derives where it counts from its files and says so"; + if (loose.length > 0) return { note: ` no component: ${loose.join(", ")} lie${loose.length === 1 ? "s" : ""} in no component; ${how}` }; + return { note: ` no component: its files lie in ${[...held].sort().join(" and ")}, so it counts toward each; ${how}` }; +} + +/** + * Where a defect lies, required at the write: --file for each file of the + * fault, or --component, or --unplaced with why no file or component of the + * project holds it. A defect with none of them counts toward no subsystem, + * so the dead-end reading could never see it; the verb asks rather than + * writes it. + */ +function defectPlace(parsed: Parsed, cwd: string): { files: string[]; component?: string; unplaced?: string; note?: string } { + const files = parsed.many.get("file") ?? []; + const component = parsed.one.get("component"); + const unplaced = parsed.one.get("unplaced"); + if (unplaced !== undefined) { + if (unplaced.trim() === "") throw new JournalError("--unplaced needs why no file or component of the project holds the fault"); + if (files.length > 0 || component !== undefined) throw new JournalError("--unplaced says no file or component holds the fault; give it, or --file/--component, not both"); + return { files, unplaced, note: " unplaced: it counts toward no subsystem's dead end, as --unplaced says" }; + } + if (files.length === 0 && component === undefined) { + const folders = componentFolders(cwd); + throw new JournalError( + `defect: say where the fault lies, or the dead-end reading counts it nowhere: --file for each file of the fault (repeatable), or --component ${folders.length === 0 ? "" : ` (components: ${folders.join(", ")})`}; when no file or component of the project holds it, --unplaced ""`, + ); + } + return { files, ...defectComponent(component, files, cwd) }; +} + export function defect(argv: string[], ctx: Context): Written { - const parsed = parseFlags(argv, withCommon({ evidence: "one", file: "many", ...ORIGIN, ...CITE })); + const parsed = parseFlags(argv, withCommon({ evidence: "one", file: "many", component: "one", unplaced: "one", ...ORIGIN, ...CITE })); const who = attribution(parsed); const what = onePositional(parsed, "what failed"); const evidence = required(parsed, "evidence", "a defect carries the reproducer or report that made it one"); - const files = parsed.many.get("file") ?? []; - const record: Defect = { ...head("defect", who, ctx, what), what, evidence, files, ...originFields(originGiven(parsed), ctx.cwd), ...citations(parsed, ctx.cwd) }; - const written = write(ctx, record); + const placed = defectPlace(parsed, ctx.cwd); + const record: Defect = { + ...head("defect", who, ctx, what), + what, + evidence, + files: placed.files, + ...(placed.component === undefined ? {} : { component: placed.component }), + ...(placed.unplaced === undefined ? {} : { unplaced: placed.unplaced }), + ...originFields(originGiven(parsed), ctx.cwd), + ...citations(parsed, ctx.cwd), + }; + const written = write(ctx, record, placed.note === undefined ? [] : [placed.note]); recordDefectTelemetry(ctx.cwd, record); return written; } @@ -404,7 +495,7 @@ function experimentClose(argv: string[], ctx: Context): Written { const parsed = parseFlags(argv, withCommon({ result: "many" })); const who = attribution(parsed); const of = onePositional(parsed, "the experiment id"); - const loaded = loadJournal(ctx.cwd); + const loaded = answerable(ctx.cwd); const open = target(loaded, of, "experiment", "experiment close"); refuseIfAnswered(loaded, of, "experiment close", ["close"]); const results: Record = {}; @@ -454,7 +545,7 @@ export function acknowledge(argv: string[], ctx: Context): Written { const who = attribution(parsed); const of = onePositional(parsed, "the escalation id"); const because = required(parsed, "because", "an acknowledgement records what the human decided"); - const loaded = loadJournal(ctx.cwd); + const loaded = answerable(ctx.cwd); target(loaded, of, "escalation", "acknowledge"); refuseIfAnswered(loaded, of, "acknowledge", ["acknowledgement"]); const record: Acknowledgement = { ...head("acknowledgement", who, ctx, `${of}\n${because}`), of, because, ...humanWords(parsed) }; diff --git a/src/journal/worktree-index.ts b/src/journal/worktree-index.ts new file mode 100644 index 00000000..7a6b87b5 --- /dev/null +++ b/src/journal/worktree-index.ts @@ -0,0 +1,134 @@ +/** + * What the reading across worktrees has already parsed, kept in the user's + * cache (userCacheDir) so an orient or a spec --check reads only the store + * files that changed since the last reading. The store files are the truth + * and this is a derivation of them: a file is taken from here only while its + * identity (device, inode, size, modification and change time) is the one + * it had when it was parsed, so any write to it, which always moves its + * change time, makes it read again. An index that is missing, unreadable, + * malformed, of another version or not this user's own answers nothing, and + * every file is read; a write that fails leaves the reading as it was. + * + * Kept per repository (its first listed worktree), never in a project: + * files each worktree's journal folder, each store file's identity and + * the digest (sha256) of its bytes + * contents each digest's records, as the keys of their lines, with the + * line or segment number each sits at + * lines each line's key (sha256 of its trimmed text) with the record + * it parses to, or the reason it does not + * Only what the current files name is kept, so the index never grows past + * the journals it derives from. + */ + +import { createHash } from "node:crypto"; +import { lstatSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, type Stats } from "node:fs"; +import { join } from "node:path"; +import { userCacheDir } from "../lifecycle/user-dir.ts"; +import type { JournalRecord } from "./record.ts"; + +const VERSION = 1; + +/** One line of a store file: the key of its trimmed text, and its 1-based number in the file. */ +export type IndexedLine = [key: string, number: number]; + +interface IndexFile { + version: number; + files: Record>; + contents: Record; + lines: Record; +} + +/** The digest a store file's bytes are known by: two files of one digest hold the same bytes, so one is parsed once. */ +export function digestOf(bytes: Buffer | string): string { + return createHash("sha256").update(bytes).digest("hex"); +} + +/** A line's key: the digest of its trimmed text, so a line already met in any file is the same record. */ +export function lineKey(trimmed: string): string { + return digestOf(trimmed); +} + +/** A store file's identity: an append changes it, and so does any other write, which can set back a modification time but never a change time. */ +export function identityOf(s: Stats): string { + return `${s.dev}:${s.ino}:${s.size}:${s.mtimeMs}:${s.ctimeMs}`; +} + +export class WorktreeIndex { + private readonly path: string | undefined; + private readonly old: IndexFile; + private readonly next: IndexFile = { version: VERSION, files: {}, contents: {}, lines: {} }; + private changed = false; + + private constructor(path: string | undefined, old: IndexFile | undefined) { + this.path = path; + this.old = old ?? { version: VERSION, files: {}, contents: {}, lines: {} }; + } + + /** The index of the repository whose first listed worktree is `main`; one that cannot be read starts empty, and `path` undefined keeps nothing. */ + static open(main: string | undefined): WorktreeIndex { + if (main === undefined) return new WorktreeIndex(undefined, undefined); + const path = join(userCacheDir(), "journal-index", `${digestOf(main).slice(0, 32)}.json`); + return new WorktreeIndex(path, readOwn(path)); + } + + /** The digest of a store file whose identity is the one it was parsed at, with its lines; undefined when it must be read. */ + known(dir: string, name: string, identity: string): { digest: string; lines: IndexedLine[] } | undefined { + const entry = this.old.files[dir]?.[name]; + if (entry === undefined || entry[0] !== identity) return undefined; + const digest = entry[1]; + const lines = this.old.contents[digest]; + if (lines === undefined) return undefined; + // Each digest's lines are checked and carried over once, however many worktrees hold the file. + if (!Object.hasOwn(this.next.contents, digest)) { + if (!lines.every(([key]) => Object.hasOwn(this.old.lines, key))) return undefined; + this.next.contents[digest] = lines; + for (const [key] of lines) this.next.lines[key] ??= this.old.lines[key]!; + } + (this.next.files[dir] ??= {})[name] = [identity, digest]; + return { digest, lines }; + } + + /** What a line's key parsed to: a record, or the reason it is none. */ + line(key: string): JournalRecord | string | undefined { + return this.next.lines[key] ?? this.old.lines[key]; + } + + /** A store file just read and parsed: kept under its identity for the next reading. */ + record(dir: string, name: string, identity: string, digest: string, lines: IndexedLine[], parsed: ReadonlyMap): void { + this.changed = true; + (this.next.files[dir] ??= {})[name] = [identity, digest]; + this.next.contents[digest] = lines; + for (const [key] of lines) this.next.lines[key] ??= parsed.get(key)!; + } + + /** Write what this reading met, when it differs from what was read: files no longer listed drop out, and with them what only they held. */ + save(): void { + if (this.path === undefined) return; + const dropped = Object.entries(this.old.files).some(([dir, names]) => Object.keys(names).some((name) => this.next.files[dir]?.[name] === undefined)); + if (!this.changed && !dropped) return; + const temporary = `${this.path}.${process.pid}.${Date.now()}.tmp`; + try { + mkdirSync(join(this.path, ".."), { recursive: true, mode: 0o700 }); + writeFileSync(temporary, JSON.stringify(this.next), { mode: 0o600 }); + renameSync(temporary, this.path); + } catch { + // The index is a derivation: one that cannot be kept leaves the next reading to read every file, as this one did. + rmSync(temporary, { force: true }); + } + } +} + +/** The index at a path, read only when it is this user's own regular file that no one else may write. */ +function readOwn(path: string): IndexFile | undefined { + try { + const s = lstatSync(path); + const me = process.getuid?.(); + if (!s.isFile() || (me !== undefined && s.uid !== me) || (s.mode & 0o022) !== 0) return undefined; + const parsed = JSON.parse(readFileSync(path, "utf8")) as Partial; + if (parsed.version !== VERSION || typeof parsed.files !== "object" || typeof parsed.contents !== "object" || typeof parsed.lines !== "object") return undefined; + if (parsed.files === null || parsed.contents === null || parsed.lines === null) return undefined; + return parsed as IndexFile; + } catch { + return undefined; + } +} diff --git a/src/lifecycle/Lifecycle.spec.md b/src/lifecycle/Lifecycle.spec.md index f23808ad..e9d27c64 100644 --- a/src/lifecycle/Lifecycle.spec.md +++ b/src/lifecycle/Lifecycle.spec.md @@ -27,6 +27,40 @@ The gyroscope delivered through harness events: orient at start, regulate at sto mirrors: TOOL_HOOKS in hook-events.ts ## invariants +- a prerelease carries main: A prerelease of Coherence is cut from a branch by .github/workflows/prerelease.yml alone, run by hand; src/lifecycle/prerelease.ts only checks, takes no arguments and runs no gh, npm or clone. prereleaseProblems refuses, naming each reason, unless the version is a prerelease, every bundled plugin and mod that follows the package (each but a 0.x one) names it and every manifest reads and names a version, each read from HEAD, a remote's URL is the repository package.json names (GitHub matched by its own host alone, the module spelling no remote or repository of its own), HEAD is on a branch of that remote with every branch fetched now by an explicit refspec and deleted ones pruned, that remote's main so fetched is an ancestor of HEAD, and that remote's tags list with no tag of the version among them, a fetch or a listing that fails being a reason, never read as a pass; the tests hold these over git fixtures. The workflow file is held only by a lint of its shape: dispatched by hand alone, read access for the workflow and its build job, contents: write for one job alone, the one that creates the release, which checks nothing out, no id-token, write-all or environment, and every action pinned by commit. What the workflow does (its build job checks the branch out by its full ref with full history and no credentials left on disk, runs the check before it installs or packs, installs the tarball in an empty folder and runs the TypeScript and Python plugin checks from it, and hands it on as an artifact; its release job creates the version's tag at the sha checked out, failing if the tag exists, and the prerelease on that tag alone, carrying the tarball, never npm) is held by how it is built and by its runs, not by any test: a text check cannot show what a workflow does. + over: a branch that holds main, then one main moved on from, a local tag named origin/main at the old main beside it, merged after; a remote set to fetch one branch while main moves on; a version the working tree holds and HEAD does not; a bundled plugin left at the version before; a manifest that does not read or names no version; a commit not pushed; one pushed only to a fork; one pushed, then its branch deleted on the remote; a clone whose only remote is a fork; a major version's bump that left a plugin behind; a version that is no prerelease; a tag that exists; a remote that cannot be read, whose tags cannot be listed; GitHub URLs in every form beside hosts that end in its name; the module's code; and the workflow file's lines: its top-level keys and trigger, each job's permissions and which job may write, every action's pin, and the YAML forms the lint does not read, which it refuses + via: a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has + because: 1.11.0-beta.1 was cut from a branch that never took main's #153, so an adopter's session start went back to saying "use these names" over a vocabulary past its cap; and npm version left the bundled plugins and the mod at the version before, found only by a reviewer; the script then cut with an untracked file the tarball shipped, with HEAD only on a fork's branch or on a branch the remote had deleted, past a local tag named origin/main, and at a major version a plugin was left behind at (the blind review of ca263d3); it then refused over symlinks git does not ignore while it would ship files git does, left main stale under a remote set to fetch fewer branches, matched any host ending in github.com, and passed over a manifest that did not read (the blind review of 887abd8); it then read versions from the working tree while it packed HEAD, passed over a manifest naming no version untested, and let a file the package's files name, never added, go unsaid (the blind review of the fixes to 887abd8); and review after review found the local script's view (its working tree, its remotes, its local refs) diverging from what would ship, so cutting moved into CI, where a pushed branch is checked out clean (2026-10-27); then a failed listing of the remote's tags read as no such tag, and the workflow's shape test, with a YAML reader of its own, passed a check step set to continue on error, a second checkout of main before the pack, a publish split across lines or spelled with an escape, and an input spliced into a quoted script, while its smoke check ran spec --check in an empty folder, which reads nothing and passed a tarball with no plugins, and the one job that ran the branch's code held contents: write (the blind review of 2558929) + refuted: dropped the check that origin/main is an ancestor of HEAD (prereleaseProblems in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (origin/main is not an ancestor of HEAD, unsaid); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: held only the package's own version, not the bundled manifests' (prereleaseProblems in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (plugins/python/plugin.json names 1.11.0-beta.2, unsaid); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: took HEAD on any remote's branch for HEAD on the release's (prereleaseProblems in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (a fork's branch is not the release's remote); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: fetched without pruning the branches the remote deleted (prereleaseProblems in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (a branch the remote deleted holds it no longer); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: read the remote's main by its short name, origin/main (prereleaseProblems in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (origin/main is not an ancestor of HEAD, unsaid); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: held only the manifests at the package's major version (versionsOf in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (plugins/python/plugin.json names 1.11.0-beta.3, not the package's 2.0.0-beta.1, unsaid); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: fell back to a remote named origin where none is package.json's (prereleaseProblems in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (no remote's URL is the repository package.json names, unsaid for a clone whose only remote is a fork); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: fetched the remote by its configured refspec, so a remote set to fetch fewer branches left main stale (prereleaseProblems in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (main fetched now, whatever branches the remote is set to fetch); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: matched GitHub by any host ending in its name (repositoryOf in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (git@evilgithub.com:PostHog/coherence.git); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: passed over a manifest that does not read (versionsOf in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (plugins/python/plugin.json does not read as a manifest naming a version, unsaid); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: read the versions from the working tree (versionsOf in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (a version the working tree holds and HEAD does not is not the release's); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: created the release without --prerelease (.github/workflows/prerelease.yml) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (marked a prerelease); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: targeted the release at the branch the ref input names instead of the sha resolved from the checkout (.github/workflows/prerelease.yml) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (--target is a step's output, never a branch's name: SHA); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: pinned setup-node by its moving tag v7 instead of a commit (.github/workflows/prerelease.yml) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (pinned by commit: actions/setup-node@v7); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: checked the branch out shallow, dropping fetch-depth: 0, so main's ancestry is not there to read (.github/workflows/prerelease.yml) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (the checkout's with, its fetch-depth: 0 missing); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: published the tarball to npm from the release step (.github/workflows/prerelease.yml) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (an npm publish); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: ran the checks after npm ci and npm pack instead of before them (.github/workflows/prerelease.yml) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (checks 5, installs 3, packs 4, releases 7, in that order); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: gave the module back a gh release create after its checks pass (src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (the module runs no gh, npm or clone); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: read a failed git ls-remote of the remote's tags as no such tag, as before (prereleaseProblems in src/lifecycle/prerelease.ts) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (origin's tags could not be listed, unsaid for a remote that cannot be read); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: gave the build job, which checks out and runs the branch's code, contents: write (.github/workflows/prerelease.yml) -> "a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has" went red in prerelease.test.ts on its own assertion (build:, which may write, is the job that releases); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- Coherence's own folder is absolute: Coherence's folders in the user's configuration (userConfigDir), where the update check and telemetry keep their files, and in the user's cache (userCacheDir), where the parse store keeps kept parses, are always absolute paths and never a throw: $XDG_CONFIG_HOME/coherence and $XDG_CACHE_HOME/coherence where each is absolute, a relative or empty one ignored as the XDG base directory spec says, else ~/.config/coherence and ~/.cache/coherence under the first absolute home of HOME, the account's in the user database and Node's, each asked without letting it throw, else a folder named for the user in the system's temporary folder, where what another user could make first is trusted only as the parse store trusts a folder, as this user's alone. + over: an absolute XDG_CONFIG_HOME and XDG_CACHE_HOME, an empty one of each, three relative ones of each, and none; HOME empty, relative, dot-relative and missing; and no account entry and no home Node can find + via: Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in + because: a relative XDG_CONFIG_HOME put the machine key that signs every kept parse in whatever folder a process started in, a project's own among them (the blind review of ca263d3); an empty or relative HOME did the same, and a repository could hold the key a process with HOME empty signed with, so its own store read as kept parses (the blind review of 887abd8); with no account entry and no home the fallback threw before it was reached, and its folder in a shared temporary folder could hold a key another user planted (the blind review of the fixes to 887abd8) + refuted: took any XDG_CONFIG_HOME that is not empty (userConfigDir in src/lifecycle/user-dir.ts) -> "Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in" went red in user-dir.test.ts on its own assertion (XDG_CONFIG_HOME="config" is ignored); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: took HOME whatever it holds (homeOf in src/lifecycle/user-dir.ts) -> "Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in" went red in user-dir.test.ts on its own assertion (HOME="" ... is absolute); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: asked Node for the home without letting it throw (homeOf in src/lifecycle/user-dir.ts) -> "Coherence's folder in the user's configuration is always an absolute path: XDG_CONFIG_HOME where it is absolute, else ~/.config under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so the machine key never lands in whatever folder a process starts in" went red in user-dir.test.ts on its own assertion (with no home anywhere: … is absolute, unsaid as the call threw); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: took a relative XDG_CACHE_HOME (userCacheDir in src/lifecycle/user-dir.ts) -> "Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in" went red in user-dir.test.ts on its own assertion (XDG_CACHE_HOME="cache" is ignored); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none - a subagent is told its own session: A subagent's start names its own session for every journal write and names its coordinator's session as one it never writes under; the main thread's start names no coordinator. over: a subagent start carrying the host's agent id beside its coordinator's session, and a main-thread start via: a subagent's start names its own session and its coordinator's, and says never to write under the coordinator's @@ -566,12 +600,12 @@ The gyroscope delivered through harness events: orient at start, regulate at sto crossing: project-source -> reading refuted: put a Coherence name an adopter writes in a journal record at risk again, as where Coherence's sense speaks -> the via went red in vocabulary-signal.test.ts at config; restored, green (2026-10-24) kinds: none -- no totals are injected: No hook injection carries a total: orient names the ranked recurring terms that lack a definition and the senses at risk, a handful at most, or says nothing; regulate names only what this session introduced. - over: every SessionStart, SubagentStart, PostToolUse and Stop injection, with nothing owed, something owed at the start, and something introduced during the session +- no totals are injected: No hook injection carries a total: orient names the ranked recurring terms that lack a definition and the senses at risk, a handful at most, or says nothing; regulate names only what this session introduced; the dead-end reading speaks at orient only when a subsystem is at a dead end, with the counts its alarm rests on, and says nothing of what it read otherwise. + over: every SessionStart, SubagentStart, PostToolUse and Stop injection, with nothing owed, something owed at the start, and something introduced during the session, over a journal holding a defect and no dead end via: no hook injection carries a total: orient names the ranked terms or says nothing because: a number nobody can act on trains an agent to skip the line it sits in, and the vocabulary line had become the one every session skipped; a short named list is something to do, and silence when nothing is owed keeps the line worth reading crossing: project-source -> reading - refuted: put the old Lexicon coverage totals line back at the head of orient's vocabulary signal -> "no hook injection carries a total: orient names the ranked terms or says nothing" went red in vocabulary-signal.test.ts; restored, green (2026-09-23) + refuted: put the old Lexicon coverage totals line back at the head of orient's vocabulary signal -> "no hook injection carries a total: orient names the ranked terms or says nothing" went red in vocabulary-signal.test.ts; restored, green (2026-09-23); later, put back orient's dead-end totals line with no dead end -> red at the SessionStart injection over a journal holding a defect; restored (cmp), green batched and alone (2026-10-27) kinds: output checklist: destination-confinement dismissed: one destination, the host's additionalContext or systemMessage, and no redirect checklist: redaction dismissed: only terms and component names are printed, never a use's text @@ -797,7 +831,7 @@ The gyroscope delivered through harness events: orient at start, regulate at sto kinds: none - a tool hook over the latency budget says so: Every hook call's time is kept, counted from its process's start; a PreToolUse or PostToolUse over the latency budget (3 s unless the config declares one) names its own time in its own answer, regulate names the session's calls over it with what the tool hooks cost in all, and orient the last week's. over: a tool hook within the budget, one over it, a session and a week of recorded calls, and a config's own budget - via: a tool hook over the latency budget says so in its own answer, and regulate and orient name the calls over it + via: a tool hook over the latency budget says so in its own answer, regulate and orient name the calls over it, and regulate names stops over it because: the tool hooks run around every tool call, so their time is paid over and over, and a call cycle that feels sluggish gets Coherence switched off, which loses every check at once; a count of git spawns guards the known shape, and the measured time catches what no count names refuted: counted a hook call's time from the call's own start, leaving out its process's start -> "a tool hook over the latency budget says so in its own answer, and regulate and orient name the calls over it" went red in stop-delivery.test.ts on its own assertion; restored byte for byte, green batched and alone (2026-10-07) kinds: budget @@ -1296,6 +1330,13 @@ The gyroscope delivered through harness events: orient at start, regulate at sto crossing: project-source -> reading refuted: said every disagreement at every watched edit, ignoring what the session was told -> "an edit that makes a list and its partner literal disagree names what each side holds alone, once per session" went red in mirrors.test.ts on its own assertion; restored byte for byte, green (2026-10-12) kinds: none +- a mirror's list is read in its own language: A declared mirror's list or partner literal in a file of a language whose plugin fills the lists slot is read by that plugin's reader (Rust's: the array a top-level const or static is set to), and one in any other file by the TypeScript reader in mirrors.ts, so a Rust list and a TypeScript list kept equal by hand are compared at the edit that makes them disagree. + over: a Rust const list mirrored by a TypeScript literal, agreeing and then broken by an edit to the Rust file + via: a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone + because: the lists slot was declared in the plugin interface and read by nothing, so a Rust list named under mirrors was said to be gone at every edit (no longer set to an array) and a project kept its Rust lists out of the alarm; the reader for a language is its plugin's, so the core reads the slot and names no language + crossing: project-source -> reading + refuted: read every mirror's list with the TypeScript reader, never the list's language's lists slot, in readLiteral -> "a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone" went red in mirrors.test.ts on its own assertion (the Rust list read as gone); restored from a copy, byte for byte, green batched and alone (2026-10-24) + kinds: none - a gone mirror is said at the edit: A write to a file a declared mirror spans, after which its list or partner literal is no longer declared as a literal there, adds a line to the edit's context saying the mirror cannot be checked and why, and the spec model names the same mirror as a problem; a mirror is never skipped in silence. over: a mirror whose list is removed from its file by an edit via: a mirror whose list is gone is said at the edit and is a spec problem, never skipped diff --git a/src/lifecycle/defect-orient.test.ts b/src/lifecycle/defect-orient.test.ts index 891d9739..79bbc984 100644 --- a/src/lifecycle/defect-orient.test.ts +++ b/src/lifecycle/defect-orient.test.ts @@ -57,11 +57,11 @@ test("orient names each guard failure under the spec block", () => { appendFileSync(join(runs, "w.jsonl"), JSON.stringify({ at: "2026-10-02T00:00:01.000Z", session: "w", agent: "w", commit: null, dirty: false, full: true, invariants: [{ component: "widget", name: "knob turns", form: "totality oracle", verdict: "pass", refutation: "witnessed", bypasses: [], testReferences: 0, files: [], reason: "green" }] }) + "\n"); const j = journal(root); const who = ["--session", "s1", "--agent", "alpha"]; - const first = j("defect", "the knob stuck", "--evidence", "turned it", "--class", "path-identity", ...who); - assert.equal(specBlock(root, ORIENT_AT), "", "a defect with no guard yet is no guard failure"); + const first = j("defect", "the knob stuck", "--evidence", "turned it", "--class", "path-identity", "--file", "widget/knob.ts", ...who); + assert.doesNotMatch(specBlock(root, ORIENT_AT), /Guard failures/, "a defect with no guard yet is no guard failure"); const close = j("resolved", first, "--because", "oiled, every knob checked", "--guard", "widget/knob turns", ...who); - assert.equal(specBlock(root, ORIENT_AT), "", "the guarded defect itself is none"); - const repeat = j("defect", "another knob stuck", "--evidence", "turned it", "--class", "path-identity", ...who); + assert.doesNotMatch(specBlock(root, ORIENT_AT), /Guard failures/, "the guarded defect itself is none"); + const repeat = j("defect", "another knob stuck", "--evidence", "turned it", "--class", "path-identity", "--file", "widget/knob.ts", ...who); const block = specBlock(root, ORIENT_AT); assert.match(block, /^Guard failures \(1\): a defect arrived in a class a guard already covered, so the guard was weaker than claimed/m); assert.match(block, new RegExp(`✕ ${repeat} in class path-identity, guarded by widget/knob turns since ${close}`)); diff --git a/src/lifecycle/hook.test.ts b/src/lifecycle/hook.test.ts index d51dcd2b..45f5ce7f 100644 --- a/src/lifecycle/hook.test.ts +++ b/src/lifecycle/hook.test.ts @@ -588,7 +588,7 @@ test("the peer feed injects a peer's decisions and escalations and no other kind // One record of every other kind a peer can write, between two the feed must carry. const decision = idOf(verb(dir, "decide", "a peer chose the store", "--because", "b", "--session", "peer-1", "--agent", "scope")); const conjecture = idOf(verb(dir, "conjecture", "a peer noticed something", "--could-be", "one", "--discriminated-by", "a test", "--session", "peer-1", "--agent", "scope")); - const defect = idOf(verb(dir, "defect", "a peer saw a deviation", "--evidence", "a report", "--session", "peer-1", "--agent", "scope")); + const defect = idOf(verb(dir, "defect", "a peer saw a deviation", "--evidence", "a report", "--file", "src/a.ts", "--session", "peer-1", "--agent", "scope")); const wall = idOf(verb(dir, "unable", "a peer hit a wall", "--because", "no password", "--session", "peer-1", "--agent", "scope")); const retraction = idOf(verb(dir, "retract", decision, "--because", "the test said otherwise", "--session", "peer-1", "--agent", "scope")); const resolution = idOf(verb(dir, "resolved", conjecture, "--because", "the test showed one", "--session", "peer-1", "--agent", "scope")); diff --git a/src/lifecycle/hook.ts b/src/lifecycle/hook.ts index 578e310c..cac23882 100644 --- a/src/lifecycle/hook.ts +++ b/src/lifecycle/hook.ts @@ -81,6 +81,7 @@ import { carried, dropCarry, rememberSaid, unsaid } from "./regulate-memory.ts"; import { HOOK_EVENTS, TOOL_HOOKS, isHookEvent, type HookEvent } from "./hook-events.ts"; import { hookLatencyOrientText, hookLatencyStopText, latencyBudget, overBudgetLine, recordHookTime } from "./hook-latency.ts"; import { syntaxOf } from "../plugins/languages.ts"; +import { parserNotice, staleParsesNotice } from "../plugins/syntax-trees.ts"; import { enforcedLanguageOf, readEnforcementConfig } from "../enforcement/config.ts"; import { viaForm } from "../plugins/verify.ts"; import { readPlugins } from "../plugins/registry.ts"; @@ -91,6 +92,7 @@ import { escapeRegExp } from "../enforcement/totality.ts"; import { keepProjectFiles } from "../adapters/project-files.ts"; import { returnFeed, leaveReturn, markChildStart, openFeed, peerFeed } from "../journal/feed.ts"; import { namedLine, openEscalations } from "../journal/read.ts"; +import { deadEndBlock, readDeadEnds } from "../journal/dead-ends.ts"; import { filesRead, lastSnapshot, patchFingerprint, recordReadTrace, recordWriteTrace, sessionPatch, snapshotSession, snapshotTrace, traceFile, type Snapshot } from "../economy/trace.ts"; import { chokepointIndex, loadSpecModel, type ChokepointEntry, type SpecModel } from "../spec/model.ts"; import { loadJournal } from "../journal/store.ts"; @@ -463,7 +465,9 @@ export function floorQuiet(runs: SpecModel["runs"], now: number): string | undef * from its language plugin's notice slot (TypeScript's: the project's * TypeScript ships no tsserver, from 7 on, and Coherence reads with its own): * said once, at the start, where the agent reads, so a reading made by - * another compiler than the project's is never a surprise. + * another compiler than the project's is never a surprise. Beside them, a + * store of kept parses a warm-up found stale (syntax-trees.ts), since a + * reading made from stale parses is as much a surprise. */ export function languageNoticeBlock(root: string): string { let languages: readonly string[]; @@ -472,7 +476,7 @@ export function languageNoticeBlock(root: string): string { } catch { return ""; } - return languages.map((language) => syntaxOf(language, "notice")?.(root) ?? "").filter((notice) => notice !== "").map((notice) => `${notice}\n\n`).join(""); + return languages.map((language) => syntaxOf(language, "notice")?.(root) ?? "").filter((notice) => notice !== "").map((notice) => `${notice}\n\n`).join("") + staleParsesNotice() + parserNotice(); } export function specBlock(root: string, now: number = Date.now()): string { @@ -491,6 +495,8 @@ export function specBlock(root: string, now: number = Date.now()): string { // that only edits keeps a floor as old as its last full run, and says so. const quiet = floorQuiet(model.runs, now); if (quiet !== undefined) lines.push(quiet); + // A subsystem collecting defects across classes and rounds after its first guard: the design is wrong, not one guard (journal/dead-ends.ts). Never shortened. + lines.push(...deadEndBlock(readDeadEnds(root, model.components, new Date(now)))); // A defect in a class already guarded: the protection was weaker than claimed (journal/defects.ts). const failures = model.defects?.guardFailures ?? []; if (failures.length > 0) { diff --git a/src/lifecycle/mirrors.test.ts b/src/lifecycle/mirrors.test.ts index 5f3131a4..676afe8d 100644 --- a/src/lifecycle/mirrors.test.ts +++ b/src/lifecycle/mirrors.test.ts @@ -138,6 +138,28 @@ test("an edit no mirror watches costs the alarm one lookup and reads no source", assert.ok(unwatched < 25 && watched < 250, `unwatched ${unwatched.toFixed(2)} ms, watched ${watched.toFixed(2)} ms`); }); +test("a list in a Rust file is read by the Rust plugin's lists slot: an edit that makes it and its TypeScript partner disagree names what each holds alone", async () => { + const root = mkdtempSync(join(tmpdir(), "coherence-mirrors-rust-")); + made.push(root); + const files: Record = { + "coherence.config.json": JSON.stringify({ name: "mirrors", language: ["typescript", "rust"] }), + "Cargo.toml": '[package]\nname = "kinds"\n', + "src/Kinds.spec.md": ["# Kinds", "", "The shape kinds.", "", "## mirrors", "- KINDS in kinds.rs: the shape kinds the kernel reads", " mirrors: SHAPE_KINDS in client.ts", "", "## invariants", ""].join("\n"), + "src/kinds.rs": '/// The kinds, kept by hand beside the client\'s.\npub const KINDS: &[&str] = &["box", /* the ground */ "plane"];\n', + "src/client.ts": 'export const SHAPE_KINDS = ["box", "plane"] as const;\n', + }; + for (const [file, text] of Object.entries(files)) { + mkdirSync(join(root, file, ".."), { recursive: true }); + writeFileSync(join(root, file), text); + } + execFileSync("git", ["init", "-q"], { cwd: root }); + keepMirrorIndex(root); + const agree = await edit(root, "src/client.ts", 'export const SHAPE_KINDS = ["box", "plane"] as const;\n// touched\n'); + assert.equal(agree.context, "", "the Rust list and its partner agree"); + const broke = await edit(root, "src/kinds.rs", 'pub const KINDS: &[&str] = &["box", "plane", "sphere"];\n'); + assert.match(broke.context, /KINDS \(src\/kinds\.rs:1\) and SHAPE_KINDS \(src\/client\.ts:1\) no longer agree: "sphere" only in KINDS/); +}); + test("a literal is read without the compiler: an array's strings, a tuple by its first, an object's keys, through a wrapping call", () => { const text = [ "export const A: readonly string[] = [\"a\", 'b', `c`, /* not */ \"d\" as const];", diff --git a/src/lifecycle/mirrors.ts b/src/lifecycle/mirrors.ts index 3bc501ce..804430b4 100644 --- a/src/lifecycle/mirrors.ts +++ b/src/lifecycle/mirrors.ts @@ -16,9 +16,10 @@ * At a watched edit, each of its mirrors is read again from the files on * disk, without the TypeScript compiler: a regular expression finds the * list's declaration, a scan that skips strings and comments finds its - * literal's top-level members, and another reads value imports, kept per - * file by size and modification time so only the files that changed are - * read. A disagreement is said as advice in the hook's context, never a + * literal's top-level members (in a language whose plugin fills the lists + * slot, that plugin's reader does both), and another reads value imports, + * kept per file by size and modification time so only the files that + * changed are read. A disagreement is said as advice in the hook's context, never a * block, and once per session until it changes; a list or a partner that is * gone is said too, never skipped. */ @@ -26,6 +27,8 @@ import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs"; import { dirname, join, relative, resolve, sep } from "node:path"; import { readProjectText } from "./work-meter.ts"; +import { languageOfFile } from "../adapters/language-files.ts"; +import { syntaxOf } from "../plugins/languages.ts"; import { escapeRegExp } from "../enforcement/totality.ts"; import { mirrorRecipeText, type MirrorRecipe } from "../spec/grammar.ts"; import { declaredMirrors, SPEC_SUFFIX, type ModelMirror } from "../spec/model.ts"; @@ -411,7 +414,11 @@ function declaredAt(mirror: IndexedMirror): string { function readLiteral(root: string, file: string, name: string): { literal: Literal } | { gone: string } { const absolute = resolve(root, file); if (!existsSync(absolute)) return { gone: `${file} is gone` }; - const literal = literalOf(readProjectText(absolute, "source"), name); + // A list in a language whose plugin fills the lists slot is read by that plugin's reader; any other file, by the TypeScript reader here. + const language = languageOfFile(file); + const provided = language === undefined ? undefined : syntaxOf(language, "lists"); + const reader = typeof provided === "function" ? provided : literalOf; + const literal = reader(readProjectText(absolute, "source"), name); if (literal === undefined) return { gone: `${name} is no longer set to an array or object literal at the top of ${file}` }; return { literal }; } diff --git a/src/lifecycle/prerelease.test.ts b/src/lifecycle/prerelease.test.ts new file mode 100644 index 00000000..e9f66b11 --- /dev/null +++ b/src/lifecycle/prerelease.test.ts @@ -0,0 +1,209 @@ +import assert from "node:assert/strict"; +import { mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { after, describe, test } from "node:test"; +import { prereleaseProblems, repositoryOf } from "./prerelease.ts"; +import { execFileSync, spawnSync } from "./work-meter.ts"; + +const fixtures: string[] = []; +after(() => { + for (const dir of fixtures) rmSync(dir, { recursive: true, force: true }); +}); + +function git(cwd: string, ...args: string[]): string { + return execFileSync("git", ["-c", "user.name=t", "-c", "user.email=t@t", "-c", "commit.gpgsign=false", ...args], { cwd, encoding: "utf8" }).trim(); +} + +/** A repository with an origin whose main the branch left, the package (naming origin as its repository) and its bundled manifests at a version. */ +function repository(version: string, pluginVersion: string = version): { work: string } { + const top = mkdtempSync(join(tmpdir(), "coherence-prerelease-")); + fixtures.push(top); + const origin = join(top, "origin.git"); + git(top, "init", "--quiet", "--bare", "--initial-branch=main", `${origin}.git`); + const work = join(top, "work"); + git(top, "clone", "--quiet", `${origin}.git`, work); + const write = (path: string, text: string): void => { + mkdirSync(join(work, path, ".."), { recursive: true }); + writeFileSync(join(work, path), text); + }; + write("package.json", JSON.stringify({ name: "@posthog/coherence", version, repository: { type: "git", url: `git+${origin}.git` } })); + write("plugins/python/plugin.json", JSON.stringify({ name: "python", version: pluginVersion })); + write("plugins/go/plugin.json", JSON.stringify({ name: "go", version: "0.1.0" })); + write("mods/coherence/.claude-plugin/plugin.json", JSON.stringify({ name: "coherence", version })); + git(work, "add", "."); + git(work, "commit", "--quiet", "-m", "start"); + git(work, "push", "--quiet", "origin", "HEAD:main"); + git(work, "checkout", "--quiet", "-b", "beta"); + git(work, "commit", "--quiet", "--allow-empty", "-m", "beta work"); + git(work, "push", "--quiet", "origin", "beta"); + return { work }; +} + +/** Main moves on without the branch, pushed from another clone of the origin. */ +function moveMain(work: string, name: string): void { + const other = join(work, "..", name); + git(join(work, ".."), "clone", "--quiet", join(work, "..", "origin.git"), other); + git(other, "commit", "--quiet", "--allow-empty", "-m", `main moves on (${name})`); + git(other, "push", "--quiet", "origin", "HEAD:main"); +} + +/** + * The workflow's lines as a lint reads them: comments and blank lines dropped, each with its indentation. A lint of + * the file's shape, not a reading of what the workflow does: it refuses the YAML forms it does not read (a tab, a node + * named with & or recalled with *, a merge key, a flow mapping, a quoted or complex key, a second document) rather than + * read past them. + */ +function workflowLines(text: string): { indent: number; text: string }[] { + const lines: { indent: number; text: string }[] = []; + for (const raw of text.split("\n")) { + const line = raw.replace(/(^|\s+)#.*$/, ""); + if (line.trim() === "") continue; + assert.doesNotMatch(line, /\t|^\s*(- )?["'?]|<<\s*:|:\s+[&*!{]|^---|^\.\.\./, `a YAML form this lint does not read: ${raw}`); + lines.push({ indent: line.length - line.trimStart().length, text: line.trim() }); + } + return lines; +} + +/** The lines under the one at index, those indented deeper than it, up to the next that is not. */ +function blockUnder(lines: { indent: number; text: string }[], index: number): { indent: number; text: string }[] { + const under: { indent: number; text: string }[] = []; + for (let i = index + 1; i < lines.length && lines[i]!.indent > lines[index]!.indent; i++) under.push(lines[i]!); + return under; +} + +/** The keys a block holds at its own level: the lines at its least indentation. */ +function keysOf(block: { indent: number; text: string }[]): string[] { + const level = Math.min(...block.map((line) => line.indent)); + return block.filter((line) => line.indent === level).map((line) => line.text); +} + +describe("a prerelease is cut only from a clean HEAD on a branch of the remote package.json names, holding that remote's main as fetched now, at a prerelease version every bundled plugin and mod that follows the package names, under a tag no release has", () => { + test("a branch that holds main, pushed, at one version throughout, may be cut", () => { + const { work } = repository("1.11.0-beta.3"); + assert.deepEqual(prereleaseProblems(work), [], "a branch that holds main, pushed and committed, at one version throughout"); + }); + + test("main moved on is refused, read by its full ref and fetched now, whatever branches the remote is set to fetch", () => { + const { work } = repository("1.11.0-beta.3"); + // The prerelease would take back what main shipped, a local tag named origin/main at the old main notwithstanding. + git(work, "tag", "origin/main", "HEAD~1"); + moveMain(work, "other"); + assert.match(prereleaseProblems(work).join("\n"), /origin\/main \([0-9a-f]+\) is not an ancestor of HEAD/); + git(work, "tag", "-d", "origin/main"); + git(work, "merge", "--quiet", "--no-edit", "origin/main"); + git(work, "push", "--quiet", "origin", "beta"); + assert.deepEqual(prereleaseProblems(work), [], "once merged and pushed, it may be cut"); + // A remote set to fetch fewer branches still has main fetched now. + git(work, "remote", "set-branches", "origin", "beta"); + moveMain(work, "mover"); + assert.match(prereleaseProblems(work).join("\n"), /origin\/main \([0-9a-f]+\) is not an ancestor of HEAD/, "main fetched now, whatever branches the remote is set to fetch"); + }); + + test("a plugin left at another version, a manifest that does not read or names no version, and a commit not pushed are each refused, every version read from HEAD", () => { + const { work } = repository("1.11.0-beta.3"); + // The versions it vouches for are HEAD's, the commit the workflow checks out, not a working tree's. + writeFileSync(join(work, "plugins", "python", "plugin.json"), JSON.stringify({ name: "python", version: "1.11.0-beta.2" })); + assert.deepEqual(prereleaseProblems(work), [], "a version the working tree holds and HEAD does not is not the release's"); + git(work, "commit", "--quiet", "-am", "python left behind"); + const problems = prereleaseProblems(work).join("\n"); + assert.match(problems, /plugins\/python\/plugin\.json names 1\.11\.0-beta\.2, not the package's 1\.11\.0-beta\.3/); + assert.doesNotMatch(problems, /plugins\/go/, "a plugin with a version of its own keeps it"); + assert.match(problems, /HEAD \([0-9a-f]+\) is on no branch of origin/); + // A major release whose bump left a plugin at the version before. + assert.match(prereleaseProblems(repository("2.0.0-beta.1", "1.11.0-beta.3").work).join("\n"), /plugins\/python\/plugin\.json names 1\.11\.0-beta\.3, not the package's 2\.0\.0-beta\.1/); + // A manifest that does not read, or names no version, is one the release cannot vouch for. + for (const [label, text] of [["does not read", "{ not json"], ["names no version", JSON.stringify({ name: "python" })]] as const) { + const broken = repository("1.11.0-beta.3").work; + writeFileSync(join(broken, "plugins", "python", "plugin.json"), text); + git(broken, "commit", "--quiet", "-am", `a manifest that ${label}`); + assert.match(prereleaseProblems(broken).join("\n"), /plugins\/python\/plugin\.json does not read as a manifest naming a version/, `a manifest that ${label}`); + } + }); + + test("HEAD only on a fork, on a branch the remote deleted, or in a clone whose only remote is a fork is on no branch of the release's remote", () => { + const { work } = repository("1.11.0-beta.3"); + git(work, "commit", "--quiet", "--allow-empty", "-m", "not pushed"); + const fork = join(work, "..", "fork.git"); + git(join(work, ".."), "init", "--quiet", "--bare", fork); + git(work, "remote", "add", "fork", fork); + git(work, "push", "--quiet", "fork", "HEAD:beta"); + assert.match(prereleaseProblems(work).join("\n"), /HEAD \([0-9a-f]+\) is on no branch of origin/, "a fork's branch is not the release's remote"); + // Pushed, then the branch deleted on the remote while this clone's tracking ref stays: fetched now, it is on no branch. + git(work, "push", "--quiet", "origin", "HEAD:beta"); + assert.doesNotMatch(prereleaseProblems(work).join("\n"), /is on no branch/); + git(work, "push", "--quiet", "origin", "--delete", "beta"); + git(work, "update-ref", "refs/remotes/origin/beta", "HEAD"); + assert.match(prereleaseProblems(work).join("\n"), /HEAD \([0-9a-f]+\) is on no branch of origin/, "a branch the remote deleted holds it no longer"); + // A clone whose only remote is a fork, as origin: no remote is the repository package.json names. + const forked = join(work, "..", "forked"); + git(join(work, ".."), "clone", "--quiet", "--branch", "beta", fork, forked); + assert.match(prereleaseProblems(forked).join("\n"), /no remote's URL is the repository package\.json names/); + }); + + test("a version that is no prerelease, a tag that exists and tags that cannot be listed are refused, GitHub is matched by its own host alone, and the script spells no remote", () => { + assert.match(prereleaseProblems(repository("1.11.0").work).join("\n"), /package\.json names 1\.11\.0, which is no prerelease/); + const tagged = repository("1.11.0-beta.3").work; + git(tagged, "tag", "v1.11.0-beta.3"); + git(tagged, "push", "--quiet", "origin", "v1.11.0-beta.3"); + assert.match(prereleaseProblems(tagged).join("\n"), /the tag v1\.11\.0-beta\.3 exists already/); + // A remote that cannot be read says nothing of its tags: that is a reason, never "no such tag". + const unread = repository("1.11.0-beta.3").work; + renameSync(join(unread, "..", "origin.git.git"), join(unread, "..", "moved.git")); + const unreadable = prereleaseProblems(unread).join("\n"); + assert.match(unreadable, /origin's tags could not be listed, so whether v1\.11\.0-beta\.3 exists is unknown/); + assert.doesNotMatch(unreadable, /exists already/); + // GitHub by its own host alone, in every form git spells it; a host that merely ends in its name is another repository. + for (const url of ["git+https://github.com/PostHog/coherence.git", "git@github.com:PostHog/coherence.git", "ssh://git@ssh.github.com:443/PostHog/coherence.git", "https://github.com/PostHog/coherence"]) assert.equal(repositoryOf(url), "github:posthog/coherence", url); + for (const url of ["git@evilgithub.com:PostHog/coherence.git", "https://notgithub.com/PostHog/coherence"]) assert.notEqual(repositoryOf(url), "github:posthog/coherence", url); + // The script names no remote and no repository of its own: every git command it runs reaches the one package.json names. + const source = readFileSync(join(import.meta.dirname, "prerelease.ts"), "utf8").replace(/^\s*(\/\/|\*|\/\*\*).*$/gm, ""); + assert.doesNotMatch(source, /["'`](origin|upstream|PostHog\/coherence)\b/, "no remote or repository is spelled in the script's code"); + }); + + test("the workflow's shape is linted, not its behaviour: dispatched by hand alone, read access but for the one job that releases, which alone may write contents and checks nothing out, no id-token or environment, every action pinned by commit; the module cuts nothing", () => { + // A lint of the file's text: what the workflow does is held by how it is built and by its runs, never by this test. + const lines = workflowLines(readFileSync(join(import.meta.dirname, "..", "..", ".github", "workflows", "prerelease.yml"), "utf8")); + const top = (key: string): number => { + const found = lines.flatMap((line, n) => (line.indent === 0 && line.text.startsWith(`${key}:`) ? [n] : [])); + assert.equal(found.length, 1, `one top-level ${key}`); + return found[0]!; + }; + assert.deepEqual(lines.filter((line) => line.indent === 0).map((line) => line.text.replace(/:.*$/, "")), ["name", "run-name", "on", "permissions", "concurrency", "jobs"], "the top-level keys, and no other"); + // Dispatched by hand, and by nothing else. + assert.equal(lines[top("on")]!.text, "on:"); + assert.deepEqual(keysOf(blockUnder(lines, top("on"))), ["workflow_dispatch:"], "dispatched by hand, and by nothing else"); + // Read access for the workflow; each job names its own, and one job alone may write contents, the one that releases. + assert.deepEqual(blockUnder(lines, top("permissions")).map((line) => line.text), ["contents: read"]); + const jobs = blockUnder(lines, top("jobs")); + const jobLevel = Math.min(...jobs.map((line) => line.indent)); + const jobStarts = jobs.flatMap((line, n) => (line.indent === jobLevel ? [n] : [])); + const writers: string[] = []; + for (const start of jobStarts) { + const name = jobs[start]!.text; + const job = blockUnder(jobs, start); + const permissions = job.findIndex((line) => line.indent === job[0]!.indent && line.text.startsWith("permissions:")); + assert.ok(permissions >= 0 && job[permissions]!.text === "permissions:", `${name} names its permissions, as a mapping`); + const granted = blockUnder(job, permissions).map((line) => line.text); + assert.ok(granted.every((grant) => /^contents: (read|write)$/.test(grant)) && granted.length === 1, `${name} holds contents alone: ${granted.join(", ")}`); + if (granted[0] === "contents: write") { + writers.push(name); + assert.ok(job.some((line) => /\bgh release create\b/.test(line.text)), `${name}, which may write, is the job that releases`); + assert.ok(!job.some((line) => /actions\/checkout@/.test(line.text)), `${name}, which may write, checks nothing out`); + } + } + assert.equal(writers.length, 1, `one job may write contents: ${writers.join(", ")}`); + assert.ok(!lines.some((line) => /\bwrite-all\b|\bid-token\b|^environment\s*:/.test(line.text)), "no write-all, no id-token (so no npm trusted publishing), and not the Release environment"); + // Every action pinned by commit. + const uses = lines.filter((line) => /\buses\s*:/.test(line.text)); + assert.ok(uses.length > 0, "the workflow uses actions"); + for (const line of uses) assert.match(line.text, /^(- )?uses: [\w.-]+\/[\w.-]+(\/[\w./-]+)?@[0-9a-f]{40}$/, `pinned by commit: ${line.text}`); + // The module cuts nothing: no gh, npm or clone in its code, so the workflow is the one way a prerelease is made; + const source = readFileSync(join(import.meta.dirname, "prerelease.ts"), "utf8").replace(/^\s*(\/\/|\*|\/\*\*).*$/gm, ""); + assert.doesNotMatch(source, /["'`](gh|npm|npx)["'`]|["'`]clone["'`]|release create/, "the module runs no gh, npm or clone"); + // and the retired local cut's arguments are refused, so no one takes the check for a cut. + const retired = spawnSync(process.execPath, ["--disable-warning=ExperimentalWarning", join(import.meta.dirname, "prerelease.ts"), "--notes", "notes.md", "--dry-run"], { encoding: "utf8" }); + assert.equal(retired.status, 2, `the local cut's arguments are refused: ${retired.stderr}`); + assert.match(retired.stderr, /cuts nothing; a prerelease is cut by CI: gh workflow run prerelease\.yml/); + }); +}); diff --git a/src/lifecycle/prerelease.ts b/src/lifecycle/prerelease.ts new file mode 100644 index 00000000..f75fad50 --- /dev/null +++ b/src/lifecycle/prerelease.ts @@ -0,0 +1,130 @@ +/** + * The checks a prerelease of Coherence must pass before it is cut from a + * branch: a GitHub prerelease carrying the package's tarball, never npm, + * which the Release environment publishes to from main alone + * (.github/workflows/release.yml). + * + * Only .github/workflows/prerelease.yml cuts one, run by hand: + * + * gh workflow run prerelease.yml -f ref= -f notes="" + * + * Its build job checks the branch out clean, with full history, runs this + * module there (node src/lifecycle/prerelease.ts, which takes no arguments + * and cuts nothing), and only when it names no reason installs, packs and + * checks the tarball; its release job then tags the commit checked out, by + * its sha, and makes the prerelease on that tag. Run anywhere + * else, it reads that clone's HEAD and remotes, which is no reading of what + * the workflow would cut: a local working tree, remote or ref is not what + * ships, and review after review found the local script's view of them + * diverging from what would. + * + * The release goes to the repository package.json names, through the remote + * whose URL is that repository's, whatever the remote is called (in the + * workflow's checkout, origin): a fork set up as origin is never released to. + * It refuses, naming each reason, unless: the version is a prerelease; every + * bundled plugin and mod that follows the package (each but a 0.x one, which + * keeps a version of its own) names this one, and every manifest reads, each + * read from HEAD; HEAD is on a branch of that remote, every branch fetched now + * by an explicit refspec, deleted ones pruned; that remote's main, so fetched, + * is an ancestor of HEAD, so the prerelease carries everything main has + * shipped; and that remote's tags list, with no tag of the version among + * them, a listing that fails being a reason too. 1.11.0-beta.1 was cut from + * a branch that never took main's #153, and put back what #153 fixed; npm + * version left the bundled plugins' versions behind the package's. + */ + +import { isAbsolute, resolve } from "node:path"; +import { spawnSync } from "./work-meter.ts"; + +/** The package's version, and every bundled manifest that follows it: each plugin's and each mod's but a 0.x one's, which keeps a version of its own. */ +export function versionsOf(repo: string): { version: string; manifests: { file: string; version: string }[]; unreadable: string[] } { + // Read from HEAD, the commit the workflow checks out and packs, never the working tree: what the release ships is what it vouches for. + const version = (JSON.parse(git(repo, "show", "HEAD:package.json").out) as { version: string }).version; + const files = git(repo, "ls-tree", "-r", "--name-only", "HEAD", "--", "plugins", "mods").out.split("\n").filter((file) => /^plugins\/[^/]+\/plugin\.json$|^mods\/[^/]+\/\.claude-plugin\/plugin\.json$/.test(file)); + const manifests: { file: string; version: string }[] = []; + const unreadable: string[] = []; + for (const file of files) { + let named: unknown; + try { + named = (JSON.parse(git(repo, "show", `HEAD:${file}`).out) as { version?: unknown }).version; + } catch { + // A manifest that will not read, or names no version, is one the release cannot vouch for. + unreadable.push(file); + continue; + } + if (typeof named !== "string") { + unreadable.push(file); + continue; + } + // A plugin with a version of its own (go, convex and quint at 0.1.0) keeps it; one that follows the package names the package's, + // whatever major version each is at, so a major release's bump that leaves one behind is caught. + if (named.split(".")[0] !== "0") manifests.push({ file, version: named }); + } + return { version, manifests, unreadable }; +} + +/** Run git in the repository: its status and its output, trimmed. */ +function git(repo: string, ...args: string[]): { ok: boolean; out: string } { + const run = spawnSync("git", args, { cwd: repo, encoding: "utf8" }); + return { ok: run.status === 0, out: `${run.stdout ?? ""}`.trimEnd() }; +} + +/** A repository's URL as one to compare: a GitHub repository by its owner/name, any other by its URL or path, as git and npm may each spell it. */ +export function repositoryOf(url: string): string { + const bare = url.replace(/^git\+/, "").replace(/\/+$/, "").replace(/\.git$/, ""); + // GitHub's own host alone, by https, ssh or scp form (git@github.com:o/r, ssh://git@ssh.github.com:443/o/r), never a host that ends in its name. + const github = /^(?:(?:https?|ssh|git):\/\/)?(?:[^@/]+@)?(?:ssh\.)?github\.com(?::\d+)?[:/]([^/]+\/[^/]+)$/.exec(bare); + if (github !== null) return `github:${github[1]!.toLowerCase()}`; + return isAbsolute(bare) ? resolve(bare) : bare; +} + +/** The repository package.json names, where a release goes, and the remote whose URL is it, or undefined where no remote's is. */ +function releaseRemote(repo: string): { url: string; remote: string | undefined } { + const named = (JSON.parse(git(repo, "show", "HEAD:package.json").out) as { repository?: string | { url?: string } }).repository; + const url = (typeof named === "string" ? named : named?.url) ?? ""; + const remote = git(repo, "remote").out.split("\n").filter(Boolean).find((name) => url !== "" && repositoryOf(git(repo, "remote", "get-url", name).out) === repositoryOf(url)); + return { url, remote }; +} + +/** Why the repository's HEAD may not be cut as a prerelease now: empty when it may. Fetches the release's remote first, pruning what it deleted. */ +export function prereleaseProblems(repo: string): string[] { + const problems: string[] = []; + const { version, manifests, unreadable } = versionsOf(repo); + if (!/^\d+\.\d+\.\d+-[0-9A-Za-z.-]+$/.test(version)) problems.push(`package.json names ${version}, which is no prerelease (1.11.0-beta.3): a release of main is release.yml's`); + for (const m of manifests) if (m.version !== version) problems.push(`${m.file} names ${m.version}, not the package's ${version}: npm version bumps package.json alone`); + for (const file of unreadable) problems.push(`${file} does not read as a manifest naming a version`); + const head = git(repo, "rev-parse", "HEAD").out; + const { url, remote } = releaseRemote(repo); + if (remote === undefined) { + problems.push(`no remote's URL is the repository package.json names (${url || "none"}), where the release goes`); + return problems; + } + // Read through the remote's own refs, fetched now: a local tag or branch named like them, or a branch the remote deleted since, says nothing. + const main = `refs/remotes/${remote}/main`; + // Every branch, by an explicit refspec, so a remote configured to fetch fewer (set-branches) still brings main and every branch now. + if (!git(repo, "fetch", "--quiet", "--prune", remote, `+refs/heads/*:refs/remotes/${remote}/*`).ok) problems.push(`${remote} could not be fetched, so whether HEAD holds its main and is on it are unknown`); + else { + if (!git(repo, "merge-base", "--is-ancestor", main, head).ok) problems.push(`${remote}/main (${git(repo, "rev-parse", "--short", main).out}) is not an ancestor of HEAD (${head.slice(0, 7)}): merge it first, or the prerelease takes back what main shipped since this branch left it`); + if (git(repo, "for-each-ref", "--contains", head, "--format=%(refname)", `refs/remotes/${remote}/`).out === "") problems.push(`HEAD (${head.slice(0, 7)}) is on no branch of ${remote}: push it, since the release's target must be there`); + } + // A listing that failed says nothing of the tag, so it is a reason too, never read as "no such tag". + const tags = git(repo, "ls-remote", "--tags", remote, `refs/tags/v${version}`); + if (!tags.ok) problems.push(`${remote}'s tags could not be listed, so whether v${version} exists is unknown`); + else if (tags.out !== "") problems.push(`the tag v${version} exists already: bump the version`); + return problems; +} + +// The workflow's check step: every reason named, and a failure when there is one. It takes no arguments and cuts nothing. +if (import.meta.main) { + // The arguments the retired local cut took (--notes, --dry-run) are refused, so no one takes a check for a cut. + if (process.argv.length > 2) { + process.stderr.write("usage: node src/lifecycle/prerelease.ts\nit checks HEAD and cuts nothing; a prerelease is cut by CI: gh workflow run prerelease.yml -f ref= -f notes=\"\"\n"); + process.exit(2); + } + const problems = prereleaseProblems(resolve(import.meta.dirname, "..", "..")); + if (problems.length > 0) { + process.stderr.write(`not cut:\n${problems.map((p) => `- ${p}`).join("\n")}\n`); + process.exit(1); + } + process.stdout.write("no reason not to cut it\n"); +} diff --git a/src/lifecycle/telemetry.ts b/src/lifecycle/telemetry.ts index 7fcceb0a..884138fa 100644 --- a/src/lifecycle/telemetry.ts +++ b/src/lifecycle/telemetry.ts @@ -22,6 +22,7 @@ import { homedir } from "node:os"; import { extname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { spawn } from "./work-meter.ts"; +import { userConfigDir } from "./user-dir.ts"; import { CAUGHT as JOURNAL_CAUGHT } from "../journal/record.ts"; import { LANGUAGES } from "../adapters/index.ts"; import { effectiveConfig, registryForLeaf } from "../adapters/project-config.ts"; @@ -79,9 +80,7 @@ export interface TelemetrySettings { /** The user's config directory for Coherence: $XDG_CONFIG_HOME/coherence or ~/.config/coherence; never inside a project. */ export function telemetryDir(env: Env = process.env): string { - const xdg = env["XDG_CONFIG_HOME"]; - const base = xdg !== undefined && xdg !== "" ? xdg : join(env["HOME"] ?? homedir(), ".config"); - return join(base, "coherence"); + return userConfigDir(env); } export const settingsPath = (env: Env = process.env): string => join(telemetryDir(env), "telemetry.json"); diff --git a/src/lifecycle/user-dir.test.ts b/src/lifecycle/user-dir.test.ts new file mode 100644 index 00000000..8e935a70 --- /dev/null +++ b/src/lifecycle/user-dir.test.ts @@ -0,0 +1,27 @@ +import assert from "node:assert/strict"; +import { isAbsolute, join } from "node:path"; +import { test } from "node:test"; +import { userCacheDir, userConfigDir } from "./user-dir.ts"; + +test("Coherence's folders in the user's configuration and cache are always absolute paths: XDG_CONFIG_HOME and XDG_CACHE_HOME where absolute, else ~/.config and ~/.cache under a home that is absolute, HOME's, the account's or Node's, else one in the temporary folder, so nothing Coherence keeps lands in whatever folder a process starts in", () => { + assert.equal(userConfigDir({ XDG_CONFIG_HOME: "/xdg", HOME: "/home/u" }), join("/xdg", "coherence")); + for (const relative of ["", "config", "./config", "../elsewhere"]) assert.equal(userConfigDir({ XDG_CONFIG_HOME: relative, HOME: "/home/u" }), join("/home/u", ".config", "coherence"), `XDG_CONFIG_HOME=${JSON.stringify(relative)} is ignored`); + assert.equal(userConfigDir({ HOME: "/home/u" }), join("/home/u", ".config", "coherence")); + // A HOME that is empty, relative or missing is no home: the folder is still an absolute path, never one under the current folder. + for (const home of ["", "rel", "./rel", undefined]) { + const dir = userConfigDir({ HOME: home, XDG_CONFIG_HOME: "config" }); + assert.ok(isAbsolute(dir) && dir.endsWith(join(".config", "coherence")), `HOME=${JSON.stringify(home)}: ${dir} is absolute`); + } + // No account entry and no home Node can find (a container's bare uid): still absolute, never a throw. + const none = { account: (): string => { throw new Error("ENOENT uv_os_get_passwd"); }, home: (): string => { throw new Error("ENOENT uv_os_homedir"); } }; + const bare = userConfigDir({ HOME: "rel" }, none); + assert.ok(isAbsolute(bare), `with no home anywhere: ${bare} is absolute`); + assert.equal(userConfigDir({ HOME: "rel" }, { account: () => "/acct", home: () => "/node" }), join("/acct", ".config", "coherence"), "the account's home before Node's"); + // The cache's folder, where kept parses go, by the same rule. + assert.equal(userCacheDir({ XDG_CACHE_HOME: "/xdg-cache", HOME: "/home/u" }), join("/xdg-cache", "coherence")); + for (const relative of ["", "cache", "./cache", "../elsewhere"]) assert.equal(userCacheDir({ XDG_CACHE_HOME: relative, HOME: "/home/u" }), join("/home/u", ".cache", "coherence"), `XDG_CACHE_HOME=${JSON.stringify(relative)} is ignored`); + for (const home of ["", "rel", undefined]) { + const dir = userCacheDir({ HOME: home, XDG_CACHE_HOME: "cache" }); + assert.ok(isAbsolute(dir) && dir.endsWith(join(".cache", "coherence")), `HOME=${JSON.stringify(home)}: ${dir} is absolute`); + } +}); diff --git a/src/lifecycle/user-dir.ts b/src/lifecycle/user-dir.ts new file mode 100644 index 00000000..e41933e0 --- /dev/null +++ b/src/lifecycle/user-dir.ts @@ -0,0 +1,57 @@ +/** + * Coherence's folders in the user's configuration and cache: + * $XDG_CONFIG_HOME/coherence, else ~/.config/coherence, where the update check + * and telemetry keep their files; and $XDG_CACHE_HOME/coherence, else + * ~/.cache/coherence, where the parse store keeps kept parses; never in a + * project. Always an absolute path: a relative one would land in whatever + * folder a process starts in. + */ + +import { homedir, tmpdir, userInfo } from "node:os"; +import { isAbsolute, join } from "node:path"; + +/** Where the user's home is asked for beyond HOME: the account's entry in the user database, and Node's own answer. */ +export interface HomeSources { + account(): string; + home(): string; +} + +const SYSTEM: HomeSources = { account: () => userInfo().homedir, home: homedir }; + +/** + * Coherence's folder in the user's cache: $XDG_CACHE_HOME/coherence where it + * is absolute, else ~/.cache/coherence under the same absolute home. What is + * kept there (parses) can be made again, and lives outside every project. + */ +export function userCacheDir(env: Record = process.env, sources: HomeSources = SYSTEM): string { + const xdg = env["XDG_CACHE_HOME"]; + if (xdg !== undefined && isAbsolute(xdg)) return join(xdg, "coherence"); + return join(homeOf(env, sources), ".cache", "coherence"); +} + +export function userConfigDir(env: Record = process.env, sources: HomeSources = SYSTEM): string { + // A relative XDG_CONFIG_HOME is invalid by the XDG base directory spec and is ignored. + const xdg = env["XDG_CONFIG_HOME"]; + if (xdg !== undefined && isAbsolute(xdg)) return join(xdg, "coherence"); + return join(homeOf(env, sources), ".config", "coherence"); +} + +/** + * The user's home as an absolute path: HOME where it is one, else the + * account's own, else Node's answer, else a folder named for the user in the + * system's temporary folder. That last one another user could make first, + * so what is kept there is trusted only as far as it is this user's alone + * (the parse store's folders: usersAlone in src/plugins/syntax-trees.ts). + */ +function homeOf(env: Record, sources: HomeSources): string { + const asked = (source: () => string): string | undefined => { + try { + return source(); + } catch { + // No account entry (a container's bare uid), or no home at all: the next candidate. + return undefined; + } + }; + for (const home of [env["HOME"], asked(sources.account), asked(sources.home)]) if (home !== undefined && isAbsolute(home)) return home; + return join(tmpdir(), `coherence-home-${process.getuid?.() ?? "user"}`); +} diff --git a/src/lifecycle/vocabulary-signal.test.ts b/src/lifecycle/vocabulary-signal.test.ts index d3940bac..1f5cf39c 100644 --- a/src/lifecycle/vocabulary-signal.test.ts +++ b/src/lifecycle/vocabulary-signal.test.ts @@ -206,9 +206,9 @@ test("a Coherence name an adopter's code declares is the project's own sense eve } }); -/** Whether a text carries a count of the population rather than names. */ +/** Whether a text carries a count of the population rather than names: the vocabulary's, or the dead-end reading's line of what it read. */ function carriesTotal(text: string): boolean { - return /\b\d+ (?:unresolved|unsettled|new\/changed|observed|contexts?|candidate)/i.test(text) || /Lexicon coverage:/.test(text); + return /\b\d+ (?:unresolved|unsettled|new\/changed|observed|contexts?|candidate|worktree)/i.test(text) || /Lexicon coverage:|Dead ends: none|defects placed by/.test(text); } function injected(stdout: string): string { @@ -220,6 +220,9 @@ function injected(stdout: string): string { test("no hook injection carries a total: orient names the ranked terms or says nothing", async () => { const root = project(); try { + // A journal holding a defect and no dead end: the dead-end reading has read something, and orient says nothing of it. + mkdirSync(join(root, ".coherence", "journal"), { recursive: true }); + writeFileSync(join(root, ".coherence", "journal", "earlier.jsonl"), JSON.stringify({ id: "df-0rient00", kind: "defect", at: new Date(Date.now() - 60_000).toISOString(), session: "earlier", agent: "a", commit: null, dirty: false, what: "the sum rounded", evidence: "a report", files: ["books/sums.ts"], component: "books" }) + "\n"); const input = { session_id: "orient-test", cwd: root }; const quiet = await runHook("SessionStart", input, root); assert.ok(!carriesTotal(injected(quiet.stdout)), injected(quiet.stdout)); diff --git a/src/observation/interfaces.ts b/src/observation/interfaces.ts index d02ef07c..68ce1c9e 100644 --- a/src/observation/interfaces.ts +++ b/src/observation/interfaces.ts @@ -20,7 +20,7 @@ import { configIgnore, projectSites } from "../adapters/project-files.ts"; import { componentOf, declarationsOf, isTest, sourceFiles } from "../economy/source.ts"; import type { EnforcementConfig } from "../enforcement/config.ts"; import type { Language } from "../adapters/index.ts"; -import { syntaxOf } from "../plugins/languages.ts"; +import { parsedOf } from "../plugins/languages.ts"; import type { SpecModel } from "../spec/model.ts"; export interface InterfaceSite { @@ -72,8 +72,8 @@ export function interfaceId(from: string, to: string): string { /** What a declaration line's keyword says can execute. */ export function declares(line: string, language: Language): InterfaceSymbol["declares"] { - // Each language's reading is its plugin's (the declares slot); a language whose plugin fills none says nothing executes. - return syntaxOf(language, "declares")?.(line) ?? "unknown"; + // Each language's reading is its parser's; a language whose plugin names none says nothing executes. + return parsedOf(language, "declares")?.(line) ?? "unknown"; } @@ -109,7 +109,7 @@ export async function readInterfaceMap(root: string, adapter: LanguageAdapter, m unanswered.set(file, error instanceof Error ? error.message : String(error)); break; } - const kind = declares(lines[declaration.line - 1] ?? "", language); + const kind = declaration.declares ?? declares(lines[declaration.line - 1] ?? "", language); for (const site of projectSites(root, references)) { if (isTest(site.file, testFolders)) continue; const from = componentOf(model, site.file)?.folder; diff --git a/src/plugins/Plugins.spec.md b/src/plugins/Plugins.spec.md index 6581a081..596fba1b 100644 --- a/src/plugins/Plugins.spec.md +++ b/src/plugins/Plugins.spec.md @@ -74,7 +74,7 @@ One interface and registry for what a project adds to Coherence: a language adap refuted: made PluginAdapter.testFilter answer with the wrapped adapter's filter until a question has loaded the plugin's module, as step 1 did -> "a plugin adapter's test filter is its own from the first ask, before any question has loaded its module" went red in languages.test.ts on its own assertion; restored from a copy, green batched and alone (2026-10-21) kinds: none - the bundled plugins load from an installed package: The package npm ships carries every bundled plugin as JavaScript under dist/bundled, its manifest naming each module as .js, so each adapter module and syntax slot loads from a project's node_modules, where Node strips no types, and the package's own commands read a project through them. - over: a scratch copy of the checkout built and packed as npm publishes it, extracted into a project's node_modules, every bundled plugin's module and syntax slots, and scaffold entrances run from the installed package + over: a scratch copy of the checkout built and packed as npm publishes it, extracted into a project's node_modules, every bundled plugin's module, syntax slots and the readings its parser derives, and scaffold entrances run from the installed package via: the bundled plugins load from an installed package: every adapter module and every syntax slot, as JavaScript, and the package's command reads a project through them because: a bundled plugin written in TypeScript cannot load from node_modules, so a package that shipped the sources alone would read no language at all wherever it is installed (the step-1 Not yet list, d-e318776a) refuted: made the build copy each bundled manifest as written, naming its modules as .ts the package does not hold (src/build.ts) -> "the bundled plugins load from an installed package: every adapter module and every syntax slot, as JavaScript, and the package's command reads a project through them" went red in bundled.e2e.ts on its own assertion; restored from a copy, green batched and alone (2026-10-21) @@ -91,8 +91,8 @@ One interface and registry for what a project adds to Coherence: a language adap because: a process that serves several projects (a registry run, the Scope live server) would read every one through the last project's plugins (review of #135) refuted: made swapsNow read the project registered last whatever forProject names (languages.ts) -> "each project's plugins answer for it alone: two projects in one process, their work interleaved, each read through its own" went red in languages.test.ts on its own assertion; restored from a copy, green batched and alone (2026-10-22) kinds: none -- a language a plugin adds is read as a bundled one is: A plugin a project names that provides a language no bundled plugin provides (Go) is that language's whole provider for that project: its files, test files, environment folders, entrance rules, CI note and steps and every syntax slot it fills are read as a bundled plugin's are, the language joins the languages the readings read, reading the config again never takes the plugin for another owner of its own files, and a project that does not name it reads none of it. - over: a project naming a fixture plugin that adds zz with every manifest field and a topLevel slot, its spec declaring one entrance whose handler a zz file declares and one it does not, a bare project read after it, and a plugin that claims a bundled language's extension +- a language a plugin adds is read as a bundled one is: A plugin a project names that provides a language no bundled plugin provides (Go) is that language's whole provider for that project: its files, test files, environment folders, entrance rules, CI note and steps, its parser and every syntax slot it fills are read as a bundled plugin's are, the language joins the languages the readings read, reading the config again never takes the plugin for another owner of its own files, and a project that does not name it reads none of it. + over: a project naming a fixture plugin that adds zz, read through Python's parser, with every manifest field and a notice slot, its spec declaring one entrance whose handler a zz file declares and one it does not, a bare project read after it, and a plugin that claims a bundled language's extension via: a plugin that provides a language no bundled plugin does is read as a bundled one is, for its project alone: its files, tests, folders, entrance rules, CI steps and syntax slots; a language nothing provides is refused by the spec check as by a run because: the registry read a new language's adapter but dropped its manifest and slots, so plugin check could never pass its file rule or declarations, a Go entrance read as a spec problem and mass read no Go, each blaming the plugin (the blind Go plugin session, 2026-10-22) refuted: made providers() read the core's languages alone, so a language a plugin adds has no file rule, folders, entrance rules or CI steps (languages.ts) -> "a plugin that provides a language no bundled plugin does is read as a bundled one is, for its project alone: its files, tests, folders, entrance rules, CI steps and syntax slots; a language nothing provides is refused by the spec check as by a run" went red in languages.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-22) @@ -103,13 +103,14 @@ One interface and registry for what a project adds to Coherence: a language adap because: a syntax slot's code runs in hook processes with the project's privileges (d-c18552a9), which the project chose but should see where the agent reads (review of #135) refuted: made the session start say nothing of a plugin whose syntax code runs in its hooks (pluginRefusalBlock in hook.ts) -> "a session start names each plugin the project brings whose syntax code runs in its hooks, once, and says nothing of the bundled ones or of a plugin with no syntax code" went red in languages.test.ts on its own assertion; restored from a copy, green batched and alone (2026-10-22) kinds: none -- a bundled plugin ejects into the project: plugin eject copies a bundled plugin's source and its check.json into the project (coherence-plugins/, or --to), its one import of the core named as @posthog/coherence/plugin, and points the config's plugins at the copy, keeping the rest of the config; it writes nothing when the folder exists, leaves the project, or the config already runs a plugin by that name from a path, and says what it wrote and what to run next; a plugin the config runs bundled is the one copied, and its copy takes that entry's place. +- a bundled plugin ejects into the project: plugin eject copies a bundled plugin's source and its check.json into the project (coherence-plugins/, or --to), its one import of the core named as @posthog/coherence/plugin and every file not a module (its parser's .wasm) byte for byte, and points the config's plugins at the copy, keeping the rest of the config; it writes nothing when the folder exists, leaves the project, or the config already runs a plugin by that name from a path, and says what it wrote and what to run next; a plugin the config runs bundled is the one copied, and its copy takes that entry's place. over: an eject into a project with a config of its own, an eject of the Go plugin a project runs bundled, and each refusal: an entry the config has by path, a folder that exists, a folder outside the project, a name no bundled plugin has via: plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has - because: a project that finds a language's plugin wanting enhances a copy of ours and swaps it in by config (d-5ec9a20a); a copy that reached into the core's modules would break with the next release's layout + because: a project that finds a language's plugin wanting enhances a copy of ours and swaps it in by config (d-5ec9a20a); a copy that reached into the core's modules would break with the next release's layout; eject read every file as text, so the TypeScript plugin's parser, once it read through one, was copied corrupt and its copy failed plugin check refuted: made plugin eject copy the plugin and leave the config unpointed (eject.ts) -> "plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has" went red in eject.test.ts on its own assertion; restored from a copy, green batched and alone (2026-10-22) refuted: staged a dynamic import('../../src/adapters/adapter.ts') in single quotes in the TypeScript plugin (typescript.ts), which a scan for from "..." misses -> "plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has" went red in eject.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-22) refuted: refused any entry the config has again, a bundled one included (ejectPlugin in eject.ts) -> "plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has" went red in eject.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-22) + refuted: read every file of the plugin as text again, its parser's .wasm among them (ejectPlugin in eject.ts) -> "plugin eject copies a bundled plugin's source and its check.json into the project, its core import named as the package's, the config pointed at it; and refuses a folder that exists or an entry the config has" went red in eject.test.ts on its own assertion (its parser copied byte for byte, never read as text); restored from a copy, byte for byte, green batched and alone (2026-10-26) kinds: none - plugin check holds a plugin to every duty: plugin check runs the duties every language plugin owes (its file rule, its declarations, every reference and none else, a chokepoint graded through the run with its refutation, and one answer each: no two slots answering with one function) over the project the plugin's check.json carries, against a bundled plugin by name or any plugin by path, and reports pass, fail or not run per duty; a plugin that reports no references fails the references duty by name, and a plugin with no check.json of its own is still held to the bundled minimum for its language. over: the bundled TypeScript plugin, a plugin in typescript's place that answers every references query with nothing, and the same plugin with no check.json of its own @@ -117,8 +118,8 @@ One interface and registry for what a project adds to Coherence: a language adap because: a swapped plugin answers every check of its language, so an enhancement that quietly reports fewer references would turn every bypass into a pass; the duties are what every bundled plugin passes, so a copy is held to what it replaced (d-5ec9a20a) refuted: made plugin check read a plugin that reports no references as one that missed some, never by name (check.ts) -> "plugin check holds a plugin to every duty, bundled or by path, and a plugin that reports no references fails, by name" went red in eject.test.ts on its own assertion; restored from a copy, green batched and alone (2026-10-22) kinds: none -- plugin check holds a language plugin to every reading of its text: plugin check runs the readings that scan a language's text (mass, the source scan's imports the economy's closure walks, the component interface reading, entrance detection) over each check project whose readings name what they recover, as a project's readings run, through the core, and passes each only where it recovers exactly that; a slot that answers in its type and reads nothing fails every reading it feeds, naming what each missed, and a plugin over no check project that names readings fails each as nothing to check. - over: a plugin in typescript's place whose source slot reads nothing, and a plugin that provides a language no bundled plugin does with no readings named +- plugin check holds a language plugin to every reading of its text: plugin check runs the readings that scan a language's text (mass, the source scan's imports the economy's closure walks, the component interface reading, entrance detection) over each check project whose readings name what they recover, as a project's readings run, through the core, and passes each only where it recovers exactly that; a reading that answers in its type and reads nothing (queries that capture nothing) fails every reading it feeds, naming what each missed, and a plugin over no check project that names readings fails each as nothing to check. + over: a plugin in typescript's place that reads through TypeScript's parser with queries that capture nothing, and a plugin that provides a language no bundled plugin does, read through Python's parser, with no readings named via: plugin check holds a language plugin to every reading of its text: a source scan that reads nothing fails mass, imports and interfaces by what each missed, and a language with no readings named fails each as nothing to check because: Rust's source slot answered in its type and read nothing, and Go filled none, and both passed every duty while a Rust or Go project got only chokepoint checks; a slot's success is what the readings that consume it recover, and no plugin waives a reading (d-6569dec0) refuted: made the reading duties pass a reading that found nothing, as if nothing were expected (compared in check.ts) -> "plugin check holds a language plugin to every reading of its text: a source scan that reads nothing fails mass, imports and interfaces by what each missed, and a language with no readings named fails each as nothing to check" went red in reading-duties.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-23) @@ -284,13 +285,14 @@ One interface and registry for what a project adds to Coherence: a language adap because: on macOS the temporary folder sits behind a link (/var is /private/var), sourcekit-lsp answered in the real path, and every site fell outside the scratch project, so plugin check failed a correct adapter (the blind Swift plugin session, 2026-10-22) refuted: made plugin check's scratch project the temporary path as made, never its real path, as before (check.ts) -> "plugin check hands the adapter its scratch project's real path, so a server that answers in real paths reports sites inside it" went red in eject.test.ts on macOS, whose temporary folder sits behind a link on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-23) kinds: none -- an empty slot is said as not read: A language whose plugin fills no source slot is named not read by mass and every reading that scans its text, with why (its plugin fills no source slot), and one whose plugin fills no interfaces slot is named not read by the component interface reading; neither is ever measured as a project of no code. - over: a plugin by path that provides a language and fills its topLevel slot alone, over a project with one file of that language - via: a plugin that fills no source slot is named not read by mass, with why, never measured as a project of no code +- an empty slot is said as not read: A language whose plugin names no parser is named not read by mass and every reading that scans its text, with why (its plugin names no treeSitter parser), the component interface reading among them; neither is ever measured as a project of no code. + over: a plugin by path that provides a language and names no parser, over a project with one file of that language + via: a plugin that names no parser is named not read by mass, with why, never measured as a project of no code because: the core stood in for an empty slot with one that reads nothing, so the Rust plugin read no text and nothing counted it until another session looked; a reading that skips a language says so (c-caa5078d) - refuted: made the language table read a plugin that fills no source slot as scanned, its reason dropped (src/plugins/languages.ts) -> "a plugin that fills no source slot is named not read by mass, with why, never measured as a project of no code" went red in plugin-coherence.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-23) + refuted: made the language table read a plugin that fills no source slot as scanned, its reason dropped (src/plugins/languages.ts) -> "a plugin that fills no source slot is named not read by mass, with why, never measured as a project of no code" (the test's title then, before pluginApi 4 removed the source slot) went red in plugin-coherence.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-23) + refuted: made the language table read a plugin that names no parser as scanned, its reason dropped (src/plugins/languages.ts languageDataTable) -> "a plugin that names no parser is named not read by mass, with why, never measured as a project of no code" went red in plugin-coherence.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-27) kinds: none -- a plugin gives each answer in one slot: No two of a bundled plugin's slots answer with one function or with two spelled alike, and plugin check fails a plugin whose do, naming both slots; the kept answers read the interfaces slot's wildcardModules, so no plugin repeats it in a kept slot. +- a plugin gives each answer in one slot: No two of a bundled plugin's slots answer with one function or with two spelled alike, and plugin check fails a plugin whose do, naming both slots; the kept answers read the parsed interfaces reading's wildcardModules, and no plugin fills a kept slot or an interfaces table's wildcardModules. over: every bundled plugin, the opt-in ones too; each slot that is a function and each function of a slot's table, a function that answers a constant left out via: no bundled plugin gives one answer in two slots: no two of its slots' functions are one function or two spelled alike because: kept and interfaces.wildcardModules were one function in TypeScript, Python and Rust; two slots asking a language one question is how their answers drift apart, and how a plugin that fills some looks whole (c-caa5078d) @@ -302,3 +304,308 @@ One interface and registry for what a project adds to Coherence: a language adap because: the core held Python's and Rust's module layout (src/enforcement/check.ts), a list of manifests and a list of basis files without a Rust crate's manifest (src/readings/scope/gaps.ts, src/readings/scope/kept-answers.ts), so an edit to that manifest refreshed neither the reading nor the kept answers refuted: named Cargo.toml in the Structure fingerprint's own list again (src/readings/scope/gaps.ts) -> "the core names no language's files: what a plugin lists as its basis or its module files appears in no core module's code, so knowledge of a language stays in its plugin" went red in plugin-coherence.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-23) kinds: none +- a language read through a parser has one reader of its text: A plugin reads its language's declarations, imports and exports only through the treeSitter parser its manifest names: the core derives the source, declares, topLevel and interfaces readings from one parse of the text (src/plugins/syntax-trees.ts, src/plugins/languages.ts parsedOf). A manifest that fills source, declares, topLevel or kept, the hand-written readers pluginApi 4 removed, never loads, whatever pluginApi it is written for and whether or not it names a parser: readManifest, which every manifest the core loads passes through, refuses it in one problem naming every such slot, the recovery of a copy ejected from an older Coherence first (eject it again from this version, the changes reapplied) and the parser path after (docs/plugins.md, Reading through a parser), so no reading of the core can meet one; a plugin of an older interface that fills none of them loads. + over: a plugin by path filling each of the four slots, written for pluginApi 1, 3 and 4, beside a parser and without one, read alone and through a config; one filling three; one extending typescript that fills the source slot; a parser alone; and a pluginApi 1 plugin that fills only the notice slot + via: a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through + because: Python's two hand-written readers of its imports disagreed: the source slot read nothing of a from-import split across lines, which the interfaces slot read whole, so mass and the economy under-counted Python reach (df-7ac38ee4); two readers of one text is how its readings drift apart + refuted: let a manifest that names a parser fill source, declares, topLevel or kept beside it, the slots it would read a second time never found (src/plugins/registry.ts treeSitterProblems) -> "a plugin that names a parser and a hand-written reader of the same text is refused, naming the slot" (the test's title then, before pluginApi 4 refused the slots without a parser too) went red in syntax-trees.test.ts on its own assertion (syntax.source beside a parser loads); restored from a copy, byte for byte, green batched and alone (2026-10-26) + refuted: refused a hand-written reader slot only beside a parser, as pluginApi 3 did, so a plugin with no parser loaded one (src/plugins/registry.ts dataProblems) -> "a plugin that fills a hand-written reader slot (source, declares, topLevel or kept) is refused naming the slot and the parser to read through instead, whatever pluginApi it is written for and whether or not it names a parser" (the test's title then, before the refusal named the eject to redo and every slot in one problem) went red in syntax-trees.test.ts on its own assertion (syntax.source at pluginApi 1 loads); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: let a manifest fill the kept slot without the refusal, so it loads through the config (src/plugins/registry.ts dataProblems) -> "a manifest that fills a hand-written reader slot (source, declares, topLevel or kept) never loads, whatever pluginApi it is written for and whether or not it names a parser, so no reading of the core can meet one: one refusal names every such slot, the eject to redo first and the parser to read through" went red in syntax-trees.test.ts on its own assertion (syntax.kept at pluginApi 1 beside a parser read as a manifest); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- an ejected copy is told to eject again: A copy plugin eject made from Coherence 1.10 or before, whose bundled language plugins filled source, declares and topLevel by hand, is refused as ejected from an older Coherence when its name is a bundled plugin's, which eject keeps and the config's key must match, naming its version and its recovery first: set its entry back to bundled, eject it again from this version into a new folder, and carry the changes into the new copy; the parser path follows for a plugin written from scratch, and a plugin no bundled one is named as is told both, the eject first. + over: the TypeScript plugin as Coherence 1.10.1's plugin eject wrote it, byte for byte (src/plugins/fixtures/ejected-1.10.1/typescript), run by path from a project's config; and a plugin of another name filling the kept slot + via: a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch + because: every bundled language manifest of 1.10.1 is pluginApi 2 and fills source, declares and topLevel by hand, so every copy eject made then is refused by pluginApi 4 (d-a59ee38f's premise that nothing but the test fixtures fills them was false); a refusal that names only the parser path sends the copy's owner to rewrite by hand what one command rewrites + refuted: told a plugin named as a bundled one nothing of its ejection, as any plugin is told (src/plugins/registry.ts handReadersRefused) -> "a copy ejected from Coherence 1.10.1 is refused as ejected from an older Coherence, its recovery named first: eject it again from this version and reapply the changes; the parser path follows for a plugin written from scratch" went red in syntax-trees.test.ts on its own assertion (the refusal did not start "plugin typescript is ejected from an older Coherence"); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- an interfaces table states facts alone: A plugin's interfaces table states only its language's facts (INTERFACE_FACTS: serverBounds); one that answers importLists, wildcardModules, isTypeDeclaration, isDefaultExport, defaultNames or any other member is refused naming each when the slot is loaded, whether or not its plugin names a parser and whether it is the provider's table or an extending plugin's wrap of it, and plugin check's one answer each duty meets the same refusal. The core reads those readings through parsedOf alone and the slot's type holds serverBounds alone, so a table's own reader could never be read. + over: a pluginApi 4 plugin whose table answers wildcardModules and importLists by hand, beside a parser and without one (the blind reviewer's probe); a table answering each of the five readings alone; an extending plugin whose wrap adds wildcardModules; and a table stating serverBounds alone + via: an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser + because: pluginApi 4 removed the kept slot, yet a plugin with no parser could answer what kept answered through its interfaces table's wildcardModules, which syntaxOf served the core, and a parser plugin's table could override isTypeDeclaration, isDefaultExport and defaultNames over the parse; a check must not trust what the checked plugin supplies, so the readings come from the parse alone (d-a5c35add) + refuted: let an interfaces table that answers readings of its text load, unrefused (src/plugins/languages.ts statedFacts) -> "an interfaces table states its language's facts alone: one that answers importLists, wildcardModules or any reading of its text is refused naming it, whether or not its plugin names a parser, and the core reads those through the parser" went red in syntax-trees.test.ts on its own assertion (missing expected exception beside a parser); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a parser reads a statement whole: Python is read through its parser and python.scm, so a from-import whose names span lines, an import inside a function or a try block, the names after the first of import a, b, a from __future__ import, and a constant whose value starts on a later line are each read, and text inside a string or a comment is never read as an import or a declaration; a lowercase module variable is bound at the top level, not declared. + over: one Python text holding each shape, through the source, topLevel and interfaces readings and the declarations mass reads + via: the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment + because: Python's line-at-a-time readers read nothing of 79,294 of PostHog's imports whose statements span lines and 8,581 inside blocks, and read 223 names out of comments and strings (x-adaa7243, df-7ac38ee4) + refuted: had the source slot read a text's imports one line at a time through the parser, as Python's hand-written reader read them (src/plugins/languages.ts treeSlot) -> "the parser reads Python's imports and declarations whole: across lines, in blocks, never inside a string or a comment" went red in syntax-trees.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a qualified use narrows a whole-module import: Where a language's queries capture a name used through a qualifier (@use.qualifier and @use.name: Go's st.Seal), a whole-module import whose bound name qualifies such uses brings in exactly those names, each joined to the module's file that declares it; the bound name is the alias the import gives, else its resolution's boundName, else the specifier's last path element. An import none of whose names the text uses that way, or whose binding no use can qualify (Go's dot and blank imports), stays whole. + over: a plugin by path reading through Python's parser with uses captured, over a three-file module: names used through the bound name, through an alias, through a name the import does not bind, none used, and a resolution that names no binding + via: a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole + because: Go names what it imports at each use, not at the import, and its hand-written reader joined an import only to the package file declaring the name used; a parser reading import statements alone would join every file of the package, losing that precision in mass and the economy (the Go plugin's move to its parser, 2026-10-26) + refuted: had the source slot hand every whole-module import whole, its qualified uses never read (src/plugins/languages.ts treeSlot) -> "a whole module the text uses names of through the name its import binds brings in those names, each joined to the module's file that declares it; one it uses no name of that way stays whole" went red in syntax-trees.test.ts on its own assertion (each name used through the name the resolution says the import binds joins the file that declares it); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- Go is read through its parser: The Go plugin reads its text through tree-sitter-go and go.scm, so a package-level func, type, var or const is declared alone or in a grouped block, each name of a list among them, exported when its first letter is upper case in Unicode's sense; a method, a field, a local, the blank identifier and text inside a comment or a raw string (one holding a package clause among them) declare nothing. + over: one Go text holding each shape, through the declarations mass reads and the topLevel reading + via: a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing + because: the hand-written reader started afresh at any line spelling a package clause, inside a raw string too, so over the Go 1.27 standard library it read 570 declarations out of raw strings and lost 649 real ones after them, and read 31 continuation lines of a multi-line value as members (the corpus comparison of the Go plugin's move to its parser, 2026-10-26) + refuted: had Go's privateName read a name private unless its first letter is an ASCII upper-case one (plugins/go/plugin.json treeSitter.privateName) -> "a Go file declares a package-level func, type, var or const, alone or in a grouped block, each name of a list; exported when its name starts upper case; a method, a field, a local, the blank identifier and a name in a comment or a raw string (a package clause in one among it) declare nothing" went red in go-source.test.ts on its own assertion (Γ read as not exported); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a path a group spells in pieces is read whole: Where a plugin's queries capture @import.prefix (a path a group of imports shares, Rust's a in use a::{b, c}), the core reads each import's specifier as every prefix whose parent node holds it after the prefix, outer first, joined to its own text by the manifest's treeSitter.separator, so groups nest to any depth with one pattern per shape; the census reads the same specifiers, and places an import whose match captures no statement in the innermost statement a match of its own captures (@import), so it can say the import sits inside a block; and queries that capture a prefix beside a manifest naming no separator are refused naming the plugin. + over: a plugin by path whose queries make a class's name a prefix of the imports in its body, two classes deep and after a nested class ends, with and without a separator; and one whose queries capture each import statement in a match apart from its imports, at the top and in a function + via: a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused + because: a query captures one node's text, and Rust's use a::{b::{c as d}} spells the path a::b::c in three nodes; the hand-written reader walked the braces as text, and a parser that read only the leaf would read c from nowhere + refuted: made the speller read an import's own node text alone, its prefixes dropped (src/plugins/syntax-trees.ts speller) -> "a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, and a prefix captured with no separator is refused" (the test's title then) went red in syntax-trees.test.ts on its own assertion (json for A::json); restored from a copy, byte for byte, green batched and alone (2026-10-26) + refuted: made the census read an import's statement only from its own match, never from a match of its own that holds it (src/plugins/syntax-trees.ts census) -> "a path a group spells in pieces is read whole: every prefix over an import, outer first, joined to it by the separator, to any depth, the census placing it in the statement that holds it, and a prefix captured with no separator is refused" went red in syntax-trees.test.ts on its own assertion (no inside a block for an import in a function); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a parser reads TypeScript whole: TypeScript and JavaScript are read through the TSX grammar and typescript.scm, and, where the TSX tree holds an error and the TypeScript grammar's errors cover less of the text, through the TypeScript grammar, the plugin's alternate, with the same queries, so a default import beside named ones (import React, { useState }), an import whose names span lines, a const enum, each name of a statement that declares several, a generic arrow function, a value asserted to a type, and a default export, declared or by name, are each read as what they are, and text inside a template string or a comment is never read as an import or a declaration; a destructured name and a name an export list exports are bound at the top level, not declared; every declaration and import after an old-style cast (value), which TSX reads as a JSX tag swallowing the rest of the file, is read as a fresh parse with the TypeScript grammar reads it, and JSX still reads through TSX. + over: one TypeScript text holding each shape, through the source, topLevel and interfaces readings and the declarations mass reads; one holding old-style casts inside a function and at the top level, with a declaration and an import after them; and a file mid-edit, a cast TSX reads as one error over the rest of the file and two typos the TypeScript grammar reads as two small ones + via: the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment + because: over PostHog's frontend (5,820 files) the hand-written readers read no named import written beside a default one (377), read 60 imports and 36 declarations out of strings and comments, and named a const enum "enum"; over Coherence's own source (352 files) they read 134 imports and 64 declarations out of its tests' fixture templates (d-dddffe34) + refuted: read no default import, the pattern that captures import x from "m" as @import.default dropped (plugins/typescript/typescript.scm) -> "the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment" went red in syntax-trees.test.ts on its own assertion (default <- react missing); restored from a copy, byte for byte, green batched and alone (2026-10-26) + refuted: dropped the TypeScript plugin's alternate parser, so only the TSX grammar reads (plugins/typescript/plugin.json treeSitter.alternate) -> "the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment" went red in syntax-trees.test.ts on its own assertion (every declaration after an old-style cast is read); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: chose between the parser's tree and the alternate's by how many errors each holds (errorSpan in src/plugins/syntax-trees.ts) -> "the parser reads TypeScript's imports, declarations and default exports whole: a default beside named imports, across lines, never inside a template or a comment" went red in syntax-trees.test.ts on its own assertion (the tree whose errors cover less of the text is read, not the one with fewer errors); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- the TypeScript parsers read what their release cannot: The TypeScript plugin's two parsers are tree-sitter-typescript 0.23.2 built with grammars/tree-sitter-typescript/coherence.patch, so an import type with type arguments, or as an array's element, an indexed type's object or keyof's operand (import('x').T, import('x').T[], keyof import('x').T), a member named in or instanceof (in?: T, in = 2, in?(): void), or beginning with in and a digit, _, $ or \ (in_progress, in2(): T, in_progress() {}), and a statement beginning so (in_flight()), on the line after another, and a bare & in JSX text or a JSX string (Billing & Usage, to="?a=1&b=2", title='Q&') each parse with no error in each grammar that reads them (JSX in the TSX grammar alone), with every declaration and import after them read, while an expression still continues onto a line that begins with the in or instanceof operator, whatever white space follows it, Unicode's among it, and a character reference (&, {) still reads as one; the unit test holds these shapes against the bundled parsers. That the patch changes nothing else over the comparison's inputs, no token renamed among it, is held in CI and not by the unit test, and over those inputs alone: a form none of them holds can read differently with every check passing, which the misread alarm catches where the misread leaves a reserved word as a name (a parser's misread is said at orient). The typescript-parsers job's comparison (grammars/tree-sitter-typescript/compare.mjs) parses tree-sitter-typescript's corpus, read from the clean upstream tree, Coherence's (corpus/coherence*.txt, kept outside the patch, one form to a case), the forms in corpus/limits.txt, TypeScript 5.9.3's lib .d.ts files and this repository's src and mods with the stock parsers and the patched ones, in both dialects, compares every node's type, named-ness, span, field and error status, and fails on any region of difference that intended-differences.json does not name by its construct (six improvements, each query naming exactly the names it fixes, and one regression: a comparison after an import type), on any of those that does not show as the one region of each corpus case it names, on any region at all in a corpus case no entry names, whatever an entry's query overlaps, so each form in corpus/limits.txt but the regression's own case reads exactly as the stock parsers read it, on any expected tree in either corpus the patched parsers do not read whole, and on any token the patched parsers read as a type the stock ones never give its spelling, inside an improvement's region as anywhere else. + over: sixteen shapes PostHog's frontend writes or a reviewer found, each alone through each bundled grammar that reads it and followed by a declaration and an import through the plugin's reading, three of them method signatures, a method after a field and a statement beginning with in_; four expressions continued by in and instanceof, two after a Unicode space; and a JSX element holding character references in its text and a string + via: the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one + because: over PostHog's frontend (5,832 files) the 0.23.2 grammars left an error in 64 files and hid 44 declarations in three (25 in marketingAnalyticsLogic.ts, 18 in incidentStatusLogic.tsx, 1 in editorSceneLogic.tsx); the patched ones leave one (an optional destructured parameter in a function type, no declaration lost) and read all 44, losing none elsewhere; over its frontend, products and common (17,106 files) 191 erring files become 52 and 85 declarations come back, none lost and no file newly erring; upstream has merged no grammar change since 0.23.2 (2024-11) and its open fix (#365) covers 7 of the 64; the first build of the bare & fix named every & operator in the TSX grammar string_fragment, which no corpus of S-expressions shows, since they leave anonymous nodes out (the blind review of ca263d3); with that fixed, the sweep of the 17,106 files reads every file as before; a text of TypeScript's operators held 74 of the TSX grammar's 143 anonymous symbols, and a build that aliased @ as string_fragment the same way passed it (the blind review of 887abd8); blind reviewers then beat both of the unit test's token checks with a token renamed to a named node (& as string_fragment, keyof as identifier), since a sample of tokens cannot show that no token was renamed, so those checks gave way to the comparison, whose 535 inputs read alike through the stock and patched parsers but for 22 regions, each one the list names; a blind reviewer then found that a check inside an improvement's region read no structure (a scanner that read no character reference passed, its & beside a bare & in one case), that the rule that every entry shows held per case, not per form (a class field named in broken back to the stock reading passed beside an interface in the same case that still showed it), and that member-named-in's query took index, input and init and missed methods, so valid source would fail CI (the blind review of 2558929) + refuted: put back the stock tree-sitter-typescript 0.23.2 parsers, unpatched (plugins/typescript/tree-sitter-typescript.wasm and tree-sitter-tsx.wasm) -> "the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling" went red in syntax-trees.test.ts on its own assertion (import type with type arguments: the tsx grammar parses it with no error); built the parsers with a semicolon scanner that ends every line before in (common/scanner.h in grammars/tree-sitter-typescript/coherence.patch) -> the same test went red on its own assertion (the tsx grammar continues an expression onto a line beginning with in or instanceof); each restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: built the parsers from e8f802e's patch, which read every character past ASCII as part of a name, a member named instanceof as the operator, and a bare & before a JSX string's quote as taking the quote (plugins/typescript/*.wasm) -> "the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling" went red in syntax-trees.test.ts on its own assertion (member named in or instanceof: the tsx grammar parses it with no error); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: built the parsers with a JSX text scanner that tells no character reference apart, so & reads as text (common/scanner.h in grammars/tree-sitter-typescript/coherence.patch) -> "the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling" went red in syntax-trees.test.ts on its own assertion (& and { are character references, in text and in a string); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: put the stock tree-sitter-typescript 0.23.2 parsers, built unpatched with tree-sitter-cli 0.27.1, in place of the bundled ones (plugins/typescript/*.wasm) -> "the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, and every operator keeps a node type of its own spelling" went red in typescript-grammar.test.ts on its own assertion (import type with type arguments: the tsx grammar parses it with no error); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: built the parsers in scratch copies of the patched grammar, each with one rename: the six a reviewer built (an & in a JSX string aliased as the string '&', so every & operator is renamed with it; keyof as typeof; & as and in intersection_type alone; the ternary's ? as ??; keyof as an identifier; & as a string_fragment in intersection_type alone) and . as ?. only in an import type with type arguments, which stands only in an improvement's region -> compare.mjs, over the build phase's corpus, failed on each: 160, 1239, 310, 5989, 1239, 309 and 1 differences it does not allow, the last the token "." read as ?. inside the region whose construct the list allows, which only the token check sees; with the patched parsers it passed (2026-10-27) + refuted: dropped jsx-string-bare-ampersand from grammars/tree-sitter-typescript/intended-differences.json -> compare.mjs failed on an unlisted improvement under a JSX string in Coherence's ampersand case (coherence-tsx); restored from a copy, byte for byte, and it passed (2026-10-27) + refuted: compared the stock parsers with themselves, as a build that lost the patch would -> compare.mjs refused before parsing: import-type-arguments' query does not compile against a parser with no type_arguments on an import type (2026-10-27) + refuted: built the parsers with a semicolon scanner that does not take = after a member named in (common/scanner.h in grammars/tree-sitter-typescript/coherence.patch), the reviewer's second break, and put them in place of the bundled ones (plugins/typescript/*.wasm) -> "the bundled TypeScript parsers read what tree-sitter-typescript 0.23.2 cannot: an import type with type arguments or as an array's element, an indexed type's object or keyof's operand, a member named in or beginning with in after another, a method among them, or a statement beginning with in after another, and a bare & in JSX text or a JSX string, each with every declaration after it, while in and instanceof still continue an expression and a character reference still reads as one" went red in typescript-grammar.test.ts on its own assertion (class field named in: the tsx grammar parses it with no error); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: compare.mjs over the same parsers -> failed on the case's expected tree (a binary_expression with an ERROR where two public_field_definitions stand) and on member-named-in showing no region in that case, its one form, in each dialect; over parsers whose scanner reads no character reference, the reviewer's first break -> failed on three expected trees and an unlisted reshape of "& ok {"; over the stock parsers' member-named-in query (^in, properties and fields alone) with the new corpus -> failed on every method case as an unlisted improvement; with the patched parsers, and with the reviewer's sources (interfaces with in_progress(), a method after a field, index beside them), it passed (2026-10-27) + refuted: built the parsers from the blind reviewer's variant of the patch, whose member_follows also accepts ( (probes/in-paren.patch.diff on common/scanner.h, the variant run), so corpus/limits.txt's "a method named in after another member" went from erring in both parsers to an improvement and member-named-in from 30 parses to 32, with intended-differences.json unchanged, which 766fba1's compare.mjs passed -> compare.mjs failed on that case in each dialect: a case no intended difference names holds an improvement under class_body, the query of member-named-in overlaps it; with the patched parsers it passed (2026-10-27) + kinds: none +- the TypeScript parsers are the ones their build makes: Both of the TypeScript plugin's parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records; the unit test holds that, and reads none of the build's scripts. What the build does is held in CI, by running it rather than by reading it: the typescript-parsers job runs fetch.sh, which downloads every input and exits on one that is not the digest inputs.sha256 records (tree-sitter-cli 0.27.1, the wasi-sdk 34 clang and binaryen 132 wasm-opt it compiles with, tree-sitter-javascript 0.23.1, TypeScript 5.9.3 and web-tree-sitter 0.27.1) and clones the upstream grammar at its pinned commit, then runs build-phase.sh in docker with --network none, which is what denies the build phase the network; the phase's own attempt to connect is a tripwire for one started with the network on, not the denial. The build phase checks every file in its inputs folder against inputs.sha256, extracts the pinned commit with replace objects ignored and refuses it unless its files hash to the tree inputs.sh pins, refuses a coherence.patch that changes any file but common/define-grammar.js and common/scanner.h, or either into anything but a regular file, and builds the patched grammar from the clean tree with those two files alone taken from the patched copy, so no file of a patch's is the corpus it is held to, though its code runs in the build (define-grammar.js under node when the grammar is generated, scanner.h in the corpus run) with the build's working folder open to it, which nothing checks; it runs tree-sitter-typescript's corpus, read from the clean tree, and Coherence's, read from corpus/ beside the scripts, in both dialects, runs the comparison, and writes nothing unless each built parser is the digest parsers.sha256 records. build.sh runs the same build phase under sandbox-exec on macOS, and on Linux in docker with --network none, or where there is no docker under unshare -rn, which leaves unix sockets on the filesystem reachable and says so. That verify waits on the job is CI's own configuration, which no test reads. + over: both bundled parsers against the digests grammars/tree-sitter-typescript/parsers.sha256 records + via: the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against + because: e8f802e's patch broke an expression continued onto a line by in before a Unicode space, which parsed with the stock grammar, and only a blind reviewer found it; a corpus of TypeScript's own declaration files and of node_modules' 873 scripts erred on the same one file under every build, broken or not, so no corpus but one that names each construct's tree catches such a break, and the grammar's own corpus had never run against the patch; the script then required emcc 6.0.13, which compiled nothing: tree-sitter-cli 0.27 compiles with a wasi-sdk clang and a binaryen wasm-opt it downloads unchecked, and the CLI itself was installed by a script that downloads its binary unchecked (the blind review of ca263d3); CI's typescript-parsers job runs the script on every pull request and verify waits on it, though main requires no check to pass before a merge; a fetch that warned instead of exiting, a final comparison replaced by true, the compiler's paths unset, an unpinned clone, a fetch through node, the CI step skipped and verify's loop exiting 0 each passed the test that matched the files' text (the blind review of 887abd8); 15 edits to build.sh and ci.yml (a fetch skipping its digest, the corpus never run, shell: true in CI among them) kept that test green, since a script's text cannot show what it does, so its text checks gave way to a build phase with no network, which checks its inputs itself; a blind reviewer then shrank infer_type in a patch that also deleted upstream's corpus cases that would expose it (Conditional types, Template literal types), and build.sh, the comparison and the corpus all passed, since the corpus was read from the patched tree and Coherence's own expected trees lived inside the patch; the clone was checked by rev-parse HEAD alone, which git replace defeats; and the network check was described as the denial when a stubbed net module passes it (the blind review of 2558929) + refuted: put e8f802e's parsers back, which build.sh no longer builds (plugins/typescript/*.wasm) -> "the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it" went red in syntax-trees.test.ts on its own assertion (the bundled typescript parser is the one build.sh builds); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: put a TypeScript parser build-phase.sh does not build in place of the bundled one, the patched grammar with & aliased as and in intersection_type alone (plugins/typescript/tree-sitter-typescript.wasm) -> "the bundled TypeScript parsers are the ones grammars/tree-sitter-typescript/build.sh builds: each is byte for byte the digest the script records and checks its build against, the script fetches nothing it does not check by its digest, its compiler among it, and CI's verify waits on the job that runs it" went red in typescript-grammar.test.ts on its own assertion (the bundled typescript parser is the one build.sh builds); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: added an unpinned curl of web-tree-sitter 0.25.0 to build-phase.sh, and ran it as CI does, in the pinned node 22.18 trixie image with docker --network none -> it stopped at the download: curl (6) could not resolve host registry.npmjs.org; restored from a copy, byte for byte, and the same run built both parsers byte for byte (2026-10-27) + refuted: ran build-phase.sh in the same container with the network left on (docker run without --network none) -> it exited 1 before reading an input: reached github.com, registry.npmjs.org, objects.githubusercontent.com, 1.1.1.1, 8.8.8.8, 140.82.112.3 (2026-10-27) + refuted: swapped web-tree-sitter 0.25.0's package in under 0.27.1's name in the inputs folder, then left a stray file beside the inputs -> build-phase.sh exited on each: web-tree-sitter-0.27.1.tgz is 560fa5a7…, not 7346db65…; extra.js is no input inputs.sha256 lists (2026-10-27) + refuted: put parsers built with a semicolon scanner that does not take = after a member named in, the blind reviewer's second break, in place of plugins/typescript/*.wasm -> "the bundled TypeScript parsers are byte for byte the digests grammars/tree-sitter-typescript/parsers.sha256 records, which the build phase checks its build against" went red in typescript-grammar.test.ts on its own assertion (the bundled typescript parser is the one build.sh builds); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: put the reviewer's harmful patch in place of coherence.patch (infer_type without its extends clause, upstream's Conditional types and Template literal types cases deleted, Coherence's corpus inside it) and ran build-phase.sh under sandbox-exec -> it exited 1 before building: coherence.patch may change common/define-grammar.js and common/scanner.h alone, and it adds test/corpus/coherence.txt and coherence-tsx.txt and changes test/corpus/types.txt; with the infer_type change alone -> tree-sitter test failed on upstream's Conditional types and Template literal types, read from the clean tree, and compare.mjs on their expected trees and two unlisted regressions; with it beside a test/corpus/coherence.txt of its own, a change to tsx/grammar.js, or common/scanner.h made a symlink -> each refused by name (A test/corpus/coherence.txt; M tsx/grammar.js; 100644 120000 T common/scanner.h); restored from a copy, byte for byte, and the same run built both parsers byte for byte, as did CI's run of it in the pinned image with docker --network none (2026-10-27) + refuted: replaced common/scanner.h's blob in the inputs' clone with git replace, which rev-parse HEAD does not see (still f975a621) -> build-phase.sh read the real blob and built both parsers byte for byte; with --no-replace-objects dropped from build-phase.sh as well -> it exited 1 before building: the commit extracts as the tree 4cd33ce3…, not 4c27006c…; restored from a copy, byte for byte (2026-10-27) + kinds: none +- a parser is held to what Coherence reads: A parser whose queries capture a name Coherence reads nothing by (but one that starts with an underscore, the queries' own for a predicate to test, which no reading reads), whose queries do not compile against it, or against its alternate parser when a text first needs the alternate (it is compiled then, so a process whose trees never err never pays for it), or that a reading asks before the process started the parser runtime, is refused naming the plugin and what to do, never read as a language with nothing in it. + over: a plugin by path with a stray capture, one with a query naming a node its parser has not, one whose alternate parser (Rust's grammar) lacks a node its queries name, read over a text its parser reads whole and one it errs on, and a process that never awaited startParsers + via: a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name + because: a query Coherence silently passed over, or a reader that answered empty before its runtime started, would read a language as one with no imports or declarations, the silent skip the reading duties exist to catch (d-6569dec0) + refuted: let a query capture a name Coherence reads nothing by, passed over in silence (src/plugins/syntax-trees.ts buildReader) -> "a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name" (the test's title since 2026-10-27) went red in syntax-trees.test.ts on its own assertion (missing expected exception); restored from a copy, byte for byte; let a reading build its parser before the runtime started, unchecked (treeReaderOf) -> the same test went red on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26) + refuted: never loaded or compiled the alternate parser, so queries that do not compile against it pass (compile in src/plugins/syntax-trees.ts) -> "a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name" went red in syntax-trees.test.ts on its own assertion (missing expected exception); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: compiled the alternate parser up front, as 45d4538 did (compile in src/plugins/syntax-trees.ts) -> "a parser is held to what Coherence reads: a capture it reads nothing by, queries that do not compile against its parser or its alternate, and a reading before the runtime starts are each refused by name" went red in syntax-trees.test.ts on its own assertion (a text the parser reads whole never asks the alternate: building the reader threw the alternate's refusal); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- every tree is freed: A reading through a parser deletes each tree it parses before it returns, however the read ends, and leaves none for the garbage collector to finalize. + over: three readings each of twenty distinct Python texts, every tree a parse makes counted until its delete() + via: every tree a reading parses is freed before the reading returns, none left to the collector + because: web-tree-sitter trees hold WebAssembly memory only delete() returns at once; 0.27 also frees a dropped tree when the collector finalizes it, which a tight run of parses outruns: with no delete, parses of a 35 KB Python text abort the process at #326 (measured on web-tree-sitter 0.27.1 for x-adaa7243), as the harness before the rebuild crashed an adopter at parse #638 of one 80 KB file (08d6f29 on the reference branch); a guard that only parsed past that count passed with delete() dropped, since the reader's own work kept the collector up, so the guard counts the trees instead (rt-36b1facf) + refuted: dropped tree.delete() after the matches are read, leaving each tree to the collector (src/plugins/syntax-trees.ts buildReader) -> "every tree a reading parses is freed before the reading returns, none left to the collector" went red in syntax-trees.test.ts on its own assertion (after 3 parses, 3 trees were never freed); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a project's parses are kept between processes: A reading through a parser keeps each text's parse in the user's cache, outside every project, filed by the parser's fingerprint and the text's digest, so a later process, in the same project or any holding the same text, parses only the texts that changed and reads the rest exactly as a fresh parse would, each from its own file; and nothing is written into any project. + over: forty Python texts read by three processes in turn for one project, the last text changed between the first and the second, then by a process for another project holding the same texts + via: a project's parses are kept between processes, in the user's cache outside every project: a later process parses only the texts that changed, and reads the rest as a fresh parse would, and any project holding the same text reads its parse + because: parsing is about 11 MB/s in WebAssembly, so mass of PostHog's Python went from 3.2 s to 14.8 s parsing every file (x-adaa7243); kept, it is 3.4 s, and a session start's pre-read of the whole project 2.0 s; the owner asked for the pre-load at session start and cheaper calls after; the parse store moved out of every project into the user's cache, its segments written once and never changed (d-d1229127), so every project, worktree and leaf of the user's shares one store; the parse store keeps each parse as a file of its own, written once, as git keeps a loose object (d-a5c35add), so a reading opens the one file it needs, and a hook that reads a file or two no longer parses its first sixteen to spare loading the store + refuted: made the kept parses answer nothing, so every process parses every text (src/plugins/syntax-trees.ts ParseStore.get) -> "a project's parses are kept between processes: a later process parses only the texts that changed, and reads the rest as a fresh parse would" went red in syntax-trees.test.ts on its own assertion (a later process parses only its first few texts and the one that changed); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a kept parse is filed under everything it depends on: A kept parse's fingerprint (fingerprintOf) digests every treeSitter input that shapes what a parse keeps, as KEPT_FROM, a record over every treeSitter key, places each: the parser's, the alternate parser's and the queries' bytes and the separator's value; the store's format; the web-tree-sitter release; and syntax-trees.ts's own source, the only module of Coherence's that code turning a tree into what is kept may live in. Each input it names changes the fingerprint; each it leaves out (privateName, resolve) changes no kept parse of any bundled plugin's check project. + over: a plugin by path reading through Python's parser, each treeSitter key varied in turn (an optional file, the alternate, a copy of the parser under its own name, so a change to it changes the fingerprint through that key alone), and every bundled plugin that reads through a parser over its check project's files; and a copy of syntax-trees.ts, as is, edited, and beside a web-tree-sitter of another release + via: a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone + because: the fingerprint digested the parser and the queries alone, while Rust's separator shapes the specifier a parse keeps, so a changed separator read parses kept under the old one; and an edit to how a tree is read kept its fingerprint, so a store outlived the code that wrote it; the owner asked how Coherence knows its fact store is not stale; dropping the web-tree-sitter release and the module's own source from the fingerprint left every test green (the blind review of 766fba1) + refuted: left the separator out of the fingerprint (KEPT_FROM in src/plugins/syntax-trees.ts) -> "a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone" went red in syntax-trees.test.ts on its own assertion (separator changes no kept parse of rust's check project); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: imported PLUGIN_API from plugin.ts at run time in syntax-trees.ts, code outside the digested module -> "a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone" went red in syntax-trees.test.ts on its own assertion (syntax-trees.ts imports at run time only the machine key's folder from the rest of Coherence); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: filed the alternate parser under its name, not its bytes (fingerprintOf in src/plugins/syntax-trees.ts) -> "a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone" went red in syntax-trees.test.ts on its own assertion (a change to the alternate file changes the fingerprint); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: left the web-tree-sitter release out of the fingerprint (fingerprintOf in src/plugins/syntax-trees.ts) -> "a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone" went red in syntax-trees.test.ts on its own assertion (a web-tree-sitter of another release changes the fingerprint); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: left the module's own source out of the fingerprint (fingerprintOf in src/plugins/syntax-trees.ts) -> "a kept parse is filed under every input it depends on: each treeSitter input KEPT_FROM names changes the fingerprint, each it leaves out changes no kept parse, and the code that reads a tree is syntax-trees.ts alone" went red in syntax-trees.test.ts on its own assertion (an edit to the module changes the fingerprint); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a reading spends bounded work on one text: Every parse and every query of a text stops past a fixed count of the parser's and the query's progress calls (PARSE_WORK_MAX, QUERY_WORK_MAX), which the same text always makes alike, so whether a text is read never depends on the machine or its load; a parse cut short resets the parser, which would otherwise resume it. A text past the bound is read as matching nothing, kept nowhere, and said at orient with its size and first line (parserNotice), and every text after it in the process is read; a warm-up whose runtime aborts anyway stops its pass, keeping what it read. + over: 900,000 lines of 1, past the parse's bound alone, and 480,000 imports, past the query's alone, then an ordinary text, warmed in one pass, then a reading of each + via: a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read + because: a source file of a=1 lines between 12 and 16 MB aborted the parser's runtime, and the warm-up, which read files up to 16 MB, went on with a dead runtime, every later text failing or the pass spinning without end, each session start launching another (the blind review of 766fba1); the runtime aborts near 8 MB of such lines, while PostHog's largest source file, a 4.9 MB generated client, makes 11,521 parse calls against 209,812 for 4 MB of a=1 lines, so the bound is work, not bytes, and a time limit would read a text on one machine and not another + refuted: spent no bound on a parse (bounded in compile, src/plugins/syntax-trees.ts) -> "a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read" went red in syntax-trees.test.ts on its own assertion (each text past a bound is read as nothing); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: left a parse cut short to resume at the next (bounded in compile, src/plugins/syntax-trees.ts) -> "a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read" went red in syntax-trees.test.ts on its own assertion (each text past a bound is read as nothing); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: spent no bound on a query (matchesOf in compile, src/plugins/syntax-trees.ts) -> "a reading spends a bounded amount of work on one text, the same on every machine: a text past it reads as matching nothing, is kept nowhere and is said at orient, and every text after it in the process is read" went red in syntax-trees.test.ts on its own assertion (each text past a bound is read as nothing); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- spelling prefixes costs what the nesting does: The import prefixes a plugin's queries capture (@import.prefix) are filed under the node that holds each, and a specifier finds the prefixes over it by walking its own ancestors, so spelling a file's specifiers costs what their nesting does, never the count of prefixes the file holds. + over: sixteen thousand grouped Rust uses in one text, read through the Rust plugin's parser + via: spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds + because: each specifier filtered every prefix in the file, so 16,000 grouped uses (309 KB) took 14.6 s and a file near the warm-up's size limit hours (the blind review of 766fba1); read by ancestors, the same text takes 245 ms + refuted: scanned every prefix the file holds for each specifier, as before (speller in src/plugins/syntax-trees.ts) -> "spelling an import's prefixes costs what its nesting does, not how many prefixes the file holds: sixteen thousand grouped uses read in a few seconds" went red in syntax-trees.test.ts on its own assertion (16,000 grouped uses read in 16902 ms); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a parser's misread is said at orient: A plugin's queries may capture @misread on a node valid source never holds, and Coherence evaluates #not-parent-type? @capture type..., which holds where the captured node's parent is none of those types, refusing by name any other predicate tree-sitter leaves unevaluated, so none is passed over as if absent. A reading whose parse holds a @misread match, from a tree with no error, leaves it in the user's cache by plugin, and orient says it for a week with its word and its line's text (parserNotice); a match in a tree with an error, whose recovery may read any word as any node, or under a parent the queries exempt, is not said. + over: a plugin reading through Python's parser whose queries capture @misread on the name boom outside a keyword argument: a text binding boom, one passing boom= as a keyword argument, one binding boom in an unclosed parenthesis, and queries using #has-parent? + via: a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name + because: the comparison that holds the patched TypeScript parsers holds them over its inputs alone, and a scanner that also took in ( as a member's name read key followed by a line beginning in (record) as a call of a function named in, with every check passing (the blind review of 766fba1); the owner asked that such a misread raise an alarm when it happens, in whatever file Coherence reads, rather than wait for a corpus that holds the form; web-tree-sitter returns a predicate it does not evaluate to the caller unapplied, so one a plugin wrote matched as if absent + refuted: evaluated no #not-parent-type?, every match kept (matchesOf in src/plugins/syntax-trees.ts) -> "a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name" went red in syntax-trees.test.ts on its own assertion (under a parent the queries exempt it is not); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: kept a @misread match from a tree with an error (Compiled.parse in src/plugins/syntax-trees.ts) -> "a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name" went red in syntax-trees.test.ts on its own assertion (in a tree with an error it is not); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: passed over a predicate nothing evaluates, as web-tree-sitter does (load in compile, src/plugins/syntax-trees.ts) -> "a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name" went red in syntax-trees.test.ts on its own assertion (a predicate nothing evaluates is refused, never passed over); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: left no misread for orient (readerOver in src/plugins/syntax-trees.ts) -> "a word a plugin's queries capture as @misread, read from a tree with no error and outside the parents they exempt, is said at orient with its line; one in an erring tree or under an exempt parent is not, and a predicate nothing evaluates is refused by name" went red in syntax-trees.test.ts on its own assertion (a misread in a tree with no error is said, with its line); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- the TypeScript plugin's misread query names no valid form: The TypeScript plugin's queries capture @misread on an identifier spelling one of TypeScript's reserved words (in, instanceof, typeof, default, return and the rest that can never bind a name), outside an import's or an export's name and export * as, where a reserved word is valid; over valid source, the in and instanceof operators across lines, labels, members and properties named by reserved words, and the plugin's own check project, it captures none. + over: export { x as default }, export { _function as function, _null as null }, export * as default, import { default as y, in as z }; in and instanceof continuing an expression across lines, for in, typeof, a labeled break; class fields and methods named in, instanceof and default, an interface member named in and delete, object keys named in, new and class, a call of o.delete(); and every file of the plugin's check.json + via: the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines + because: over 171,579 TypeScript and JavaScript files of PostHog's and of node_modules, read through the bundled parsers, every reserved word an error-free tree held as an identifier stood under import_specifier, export_specifier or namespace_export (29,372 export { x as default } among them), and every other one stood in a tree with an error; an alarm that fires on valid source teaches its reader to pass it over + refuted: dropped the exemption of an import's or an export's name from @misread (plugins/typescript/typescript.scm) -> "the TypeScript plugin's queries capture no misread where valid TypeScript binds a reserved word or uses one as an operator: an import's or an export's name, export * as, and in, instanceof, typeof, labels and members across lines" went red in syntax-trees.test.ts on its own assertion (no misread in export { x as default }); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none + +- a warm-up audits what is kept: The warm-up a session start launches parses again a sample of the texts its kept parses answer (eight, chosen evenly over the pass) and holds each kept parse to the fresh one; where any differs, the store of that fingerprint is removed whole, the readings after it in the process read fresh parses, and the warm-up leaves an audit in the user's cache that orient says for a week (staleParsesNotice). + over: forty Python texts warmed four times, the third over a store whose every kept parse was rewritten to hold another import; the notice read at once and eight days on; then only the texts after the eighth made stale + via: a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week + because: a fingerprint is a claim about what a parse depends on, and a claim missed is a store read as true by every reading until the fingerprint changes for another reason; a sample checked at each warm-up turns a missed input into a notice within a session, and the owner asked how Coherence knows its fact store is not stale; the parse store moved out of every project into the user's cache, its segments written once and never changed (d-d1229127); a sample of the first eight texts in place of one chosen over the pass left the test green (the blind review of 766fba1) + refuted: made the audit compare nothing, so every sampled kept parse agrees (warmParses in src/plugins/syntax-trees.ts) -> "a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week" went red in syntax-trees.test.ts on its own assertion (the audit finds the sample stale, and a reading after it reads a fresh parse); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: said an audit.json without checking this machine's signature (staleParsesNotice in src/plugins/syntax-trees.ts) -> "a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is discarded whole, the readings after it read fresh, and orient says so for a week" went red in syntax-trees.test.ts on its own assertion (and only on the machine whose warm-up wrote it); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: sampled the first eight kept texts of the pass (warmParses in src/plugins/syntax-trees.ts) -> "a warm-up holds a sample of its kept parses to a fresh parse of the same text: a store that differs is removed whole, the readings after it read fresh, and orient says so for a week" went red in syntax-trees.test.ts on its own assertion (a sample chosen over the whole pass meets the texts after its first eight); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- two slots that answer one question agree: plugin check's answers agree duty runs, over every file of each check project, the readings that answer one question of the same text and fails naming the file and the name where they disagree: a name the source scan finds declared that the topLevel reading finds no top-level declaration of, a type declaration where the interfaces reading of its line alone and the declares reading of the whole text say otherwise (queries that read a declaration by what surrounds it), or a name an interfaces import list renames that the source scan reads no import of. An unknown kind is no answer and is never compared. + over: a plugin by path reading through Python's parser whose queries read a decorated class as a type and an undecorated one as a body, so a decorated class's line alone reads as a body, and the same plugin with Python's own queries; and every bundled language plugin's check project + via: plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name + because: Python's source scan read nothing of a from-import split across lines while its interfaces slot read it whole, and no duty ran the two over the same text (df-7ac38ee4); a question answered twice drifts apart unless the answers are compared + refuted: let a name an import list renames pass whether or not the source scan reads it imported (src/plugins/check.ts answersAgree) -> "plugin check fails a plugin whose two readers of one text disagree: an import list renaming a name the source scan never reads imported, named by file and name" (the test's title then, over Python's two hand-written readers, which pluginApi 4 can no longer load) went red in answers-agree.test.ts on its own assertion (actual pass); restored from a copy, byte for byte, green batched and alone (2026-10-26) + refuted: let a type declaration pass whether or not the interfaces slot and the declares reading agree on it (src/plugins/check.ts answersAgree) -> "plugin check fails a plugin whose two readers of one text disagree: an interfaces table that reads a type declaration where the parser reads none, named by file and name" (the test's title then, before pluginApi 4 refused an interfaces table's own isTypeDeclaration) went red in answers-agree.test.ts on its own assertion (actual pass); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: let a type declaration pass whether or not the interfaces reading of its line and the declares reading of the whole text agree (src/plugins/check.ts answersAgree) -> "plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name" went red in answers-agree.test.ts on its own assertion (actual pass); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- every bundled language plugin passes its own plugin check: Each bundled plugin that provides a language passes every duty plugin check holds it to over its own check project, the adapter's references and chokepoint among them, so a check project edited for one duty cannot stand stale for another. + over: every bundled plugin that provides a language (TypeScript, Python, Rust, Go), each over its own check.json, through its real language server + via: every bundled language plugin passes every duty of its own plugin check + because: Python's check project gained a from-import spanning lines while its references and bypasses still named the old lines, and the test that ran its whole plugin check asserted only the reading duties, so the bundled plugin failed its own check with every test green (df-11317061) + refuted: left one of Python's check project's references a line off from the file it names, render.py:12 for :13, as df-11317061 left them after the file changed (plugins/python/check.json) -> "every bundled language plugin passes every duty of its own plugin check" went red in reading-duties.test.ts on its own assertion (python's own plugin check: references missed shop/api/render.py:12); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a shape a project writes and no check project holds is named: coherence plugin shapes reads every source file of each language the project reads through a parser, counts each shape of import it writes (named, renamed, glob, whole module, spans lines, inside a block) beside the count the plugin's check projects put to it (only an import that resolves to a file of the check project, the ones the imports duty compares, in the check projects plugin check reads for the language), and names each shape the project writes that no check project holds as untested, with where the project first writes it; a language read without a parser is said not read, never counted as holding no imports. + over: a project whose one file writes every shape, its plugin's check project holding one named import on one line + via: plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds + because: Python's check project held no import spanning lines while 14% of PostHog's imports span lines, so plugin check never put that shape to the reader that missed every one (df-7ac38ee4); on PostHog the census names renamed, glob, whole module and inside a block untested, which Python's check project now holds + refuted: made the reading name a shape untested only where the check projects hold fewer than none, so none is ever named (src/plugins/shapes.ts shapesText) -> "plugin shapes counts each shape of import the project writes beside its plugin's check projects, and names each the project writes that no check project holds" went red in shapes.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a text reading is held to the language server's account: plugin check's server agrees duty asks the plugin's adapter (or the one it wraps) for each check project file's top-level symbols and fails naming the file, line and name of every declaration the text reading finds that the server reports no top-level symbol of; a name the server reports that the reading leaves out is no failure, and an adapter that offers no topLevelSymbols reads not run with why. + over: a plugin by path reading through Python's parser, beside a stand-in server whose account lacks a function the parse declares; and every bundled language plugin's check project through its real server + via: plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line + because: the text readings are Coherence's instruments, and nothing held them to an independent account: Python's line scan read 223 of PostHog's names out of strings and comments, found only when a parser was set beside it (x-adaa7243) + refuted: let a declaration the server reports no symbol of pass (src/plugins/check.ts serverAgrees) -> "plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line" went red in answers-agree.test.ts on its own assertion (actual pass); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- plugin calibrate counts misreads and what the server alone reports: coherence plugin calibrate holds each language's text reading to its language server over the project's first source files in path order, and prints how many of the reading's declarations the server reports too, each it does not as a misread with its file and line, and what the server reports that the reading leaves out counted by symbol kind; a language whose adapter offers no topLevelSymbols, or whose server is not up, is said not run with why. + over: a project whose plugin reads through Python's parser, beside a stand-in server whose account lacks a function the parse declares and also reports a lowercase variable the reading leaves out + via: plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind + because: a reading's misses and misreads were found once, by a corpus diff written for one experiment (x-adaa7243); calibrating against the server the adapter already drives makes it a reading any project can take + refuted: counted every declaration the reading finds as one the server reports too (src/plugins/calibrate.ts) -> "plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind" went red in calibrate.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- every language plugin reads the reference project alike: Each language plugin's check project maps its files and names onto the reference project (a store of two files, secrets declaring SECRET_COLUMNS and seal and rows declaring Row; a render using all three; a main using render), and plugin check's reference reading duty fails naming each relation the plugin's readings do not recover over it; coherence plugin compare lays every language plugin's reading of it side by side, bundled and the project's, and names each plugin that reads a relation another way. A check project that maps none is held only where no other check project of the plugin maps it. + over: a plugin by path whose resolve gives an import of a two-file module its first file alone, beside the four bundled language plugins (TypeScript, Python, Rust, Go), each over its own check project + via: plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way + because: four plugins picked the file a module import reaches four ways, and each missed a file of a two-file module its importer used (d-cb7829df); nothing compared two plugins' readings of the same shape of project, so each plugin's divergence passed its own check + refuted: counted a reference relation held when the reading found no import from that file at all (src/plugins/check.ts referenceRelations) -> "plugin compare lays every language plugin's reading of the reference project side by side, and names a plugin that reads a relation another way" went red in reference.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- the parse store never reaches past the project's own folders: The parse store reads and writes nothing of any project's: its files are in the user's cache (userCacheDir), never in a project, so a project's own .coherence/parses, a forged store, a log, a lock or an audit among it, is never read, written or said at a session start; and the store is used only where the user's cache is the user's alone (a kept parse is read only where it is the user's alone), so a cache folder others may write, or a link to one, keeps nothing and every text is parsed. + over: a project holding what an older Coherence kept in it (a store forged with a made-up import, a log, a live lock, audits in the plugin's folder and in one named as an instruction), its .coherence listed by name, size and time before and after a warm-up and a reading; and a cache whose folder others may write, and one whose folder is a link to a folder others may write + via: the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing + because: the warm-up removed every entry of .coherence/parses// but its store, through a link, so a repository committing that folder as a link to ~/.ssh had a session start empty it; it shipped in the prerelease v1.11.0-beta.0, which was deleted (df-7c50adfe); a store a contributor force-adds would otherwise feed made-up imports to every clone's readings; removing the checks on .coherence and .coherence/parses, or O_NOFOLLOW on a read, left every test green, and an append went through a hard link a repository's archive can carry (the blind review of ca263d3); the parse store moved out of every project into the user's cache, its segments written once and never changed (d-d1229127): no file a repository commits is the store's, so every defence against one (signing, generations, links, pipes, planted locks and audits) is no longer needed + refuted: made the store's path check pass whatever lies on the path, links among it (src/plugins/syntax-trees.ts ParseStore.safe) -> "the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed" went red in syntax-trees.test.ts on its own assertion (a link on the store's path keeps no parses); restored from a copy, byte for byte, green batched and alone (2026-10-26) + refuted: signed the store's fingerprint alone, not its contents, as 1.11.0-beta.1 did (ParseStore.sign in src/plugins/syntax-trees.ts) -> "the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed" went red in syntax-trees.test.ts on its own assertion (made_up <- forged read where b <- a was expected); before the forged body was made well formed, this break left the test green, since the shape check refused the body first; restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: made the store's folder check pass whatever lies on the path (StoreFolder's #safe in src/plugins/syntax-trees.ts) -> "the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed" went red in syntax-trees.test.ts on its own assertion (a link on the store's path keeps no parses); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: opened the store's files to read without O_NOFOLLOW (StoreFolder's #open in src/plugins/syntax-trees.ts) -> "the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed" went red in syntax-trees.test.ts on its own assertion (a signed store linked in from outside is never read); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: appended to a file whatever its count of names (StoreFolder.append in src/plugins/syntax-trees.ts) -> "the parse store never reaches past the project's own folders: a link on its path, at .coherence, at its parses or at a plugin's folder, keeps no parses and touches nothing, a store or log the project brings is never read or written through, by a link or a second name, and only the store's own files are removed" went red in syntax-trees.test.ts on its own assertion (nothing is appended to a file with a second name); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: judged the cache's folders by the path as written, no link followed (usersAlone in src/plugins/syntax-trees.ts) -> "the parse store lives outside every project and is used only where the user's cache is the user's alone: a project's own .coherence/parses, a forged store, a log, a lock and an audit among it, is never read or written, and a cache others may write, or a link to one, keeps nothing" went red in syntax-trees.test.ts on its own assertion (a cache folder that is a link to a folder others may write keeps nothing); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a kept parse is read only where it is the user's alone: The parse store is used only where no one but the user and the system can change what its path leads to (usersAlone): every folder and link on the path to the store's folder, as written and once every link is followed, owned by the user or the system, and no folder on it that others may write unless it is sticky, as the system's temporary folder is, or only its group may and that group is the user's own alone (the user's primary group, named as the user, with no other member, as Debian and Ubuntu make one); the store's folder and the one it is in the user's own that no one else may write. Where the store is not used, orient says so and names the folder that keeps it off (parserNotice). Access lists (macOS ACLs) are not read: a folder whose mode keeps others out but whose access list lets them in passes. Each kept parse is read only where its folder is the user's own that no one else may write, and it is the user's own regular file, no link, that no one else may write, of at most 32 MB; anything else answers nothing, and the text is parsed. + over: a forged kept parse planted where the text's would be, read in a store of the user's alone, then with its store folder others may write, its own folder others may write, the file others may write, the file a link to another, and a folder on the way to the cache others may write; orient's notice for the folder others may write; a cache reached through a link in a folder others may write that leads to a folder of the user's own; and a kept parse of a parse's shape past 32 MB + via: a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed + because: the store trusted a cache folder only by its own owner and mode, so a folder above it that others may write let another user move the cache away and put a store of theirs in its place, and a fingerprint's folder, never checked, could be made one others may write (the blind review of 2558929); a check of the whole path, as written and as followed, and of each file read leaves no folder on the way a stranger could change after the check; the parse store keeps each parse as a file of its own, written once, as git keeps a loose object (d-a5c35add); a cache reached through a link in a folder others may write was still read with the walk of the path as written removed, a kept parse past 32 MB was read with the size bound removed, the tests green both times, and a group-writable ~/.cache, the default where each user has a group of their own, turned the store off with nothing said (the blind review of 766fba1) + refuted: read a kept parse whatever its folder (ParseStore.get in src/plugins/syntax-trees.ts) -> "a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed" went red in syntax-trees.test.ts on its own assertion (a kept parse's folder others may write); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: read a kept parse others may write (ownFile in src/plugins/syntax-trees.ts) -> "a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed" went red in syntax-trees.test.ts on its own assertion (a kept parse others may write); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: opened a kept parse following a link (ownFile in src/plugins/syntax-trees.ts) -> "a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed" went red in syntax-trees.test.ts on its own assertion (a kept parse that is a link); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: checked the store's folder and the one it is in, none above (usersAlone in src/plugins/syntax-trees.ts) -> "a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed" went red in syntax-trees.test.ts on its own assertion (a folder on the way others may write); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: checked the parses folder alone, never a fingerprint's (ParseStore.of in src/plugins/syntax-trees.ts) -> "a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed" went red in syntax-trees.test.ts on its own assertion (a store folder others may write); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: judged the store's path only as followed, never as written (whyNotUsersAlone in src/plugins/syntax-trees.ts) -> "a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed" went red in syntax-trees.test.ts on its own assertion (a cache reached through a link in a folder others may write); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: read a kept parse of any size (ownFile in src/plugins/syntax-trees.ts) -> "a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed" went red in syntax-trees.test.ts on its own assertion (a kept parse past 32 MB); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: said nothing when the store is off (parserNotice in src/plugins/syntax-trees.ts) -> "a kept parse is read only where it is the user's alone: a store folder, or a kept parse's folder, that others may write, a folder on the way to the cache others may write, a kept parse that is a link, and one that others may write, each answers nothing, and the text is parsed" went red in syntax-trees.test.ts on its own assertion (and orient says the store is off, and why); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a store inside the repository is never used for it: A parse store inside the repository a project is read from (the nearest folder up holding .git), as a cache set inside a checkout puts it, is never used for that project, its top or a leaf below it read (ParseStore.outside), so files the repository commits there never answer its readings; a store elsewhere is. + over: a repository that commits a store under .cache, holding a parse of its own making, read with XDG_CACHE_HOME set to that folder, at its top and at a leaf below it + via: a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read + because: a CI cache is often set inside the checkout (GitLab requires a cached path to be in the project), where a checkout's files are the CI user's own and of a mode no one else may write, so they passed every check of the user's cache and a repository committing a store there handed its readings parses of its own making (the blind review of 766fba1); the nearest .git, not the farthest, so a home folder kept as a repository of its own refuses no project's store + refuted: used a store wherever it lies (ParseStore.outside in src/plugins/syntax-trees.ts) -> "a parse store inside the repository a project is read from is never used for it, however the cache is set, the repository's top or a leaf below it read" went red in syntax-trees.test.ts on its own assertion (the store inside the repository is not read for its top); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a repository cannot stop a warm-up or speak through the store: A source file nested ten thousand deep around an error is read, and the file after it; a project's source file that links out of the project, that stands in a folder that links out of it, to a pipe, or that is larger than 16 MB is never read by the warm-up, which finishes; and since the store holds no file of the project's, nothing a repository commits stops a warm-up or speaks at a session start. + over: a Python file nested ten thousand deep around an error before another, and a TypeScript one; a project whose source holds a link to a file outside it, a link to a pipe and an 18 MB file + via: a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes + because: the fingerprint is the same for every user of a release, so a repository can name the store's file before a warm-up writes it, and a folder there made every warm-up throw; a committed lock of a live pid stamped ahead held every warm-up off for good; and an unsigned audit.json put a false defect, under a folder name of the repository's choosing, into every session start (the blind review of 413b9a6); a 20 KB file of parentheses nested around an error overflowed the stack of the recursion that measured a tree's errors, so every warm-up and every mass threw; a lock no warm-up could read held every warm-up off for good; and the warm-up followed a project's links, keeping names out of a file outside it and hanging on a pipe (the blind review of ca263d3); the taking-over lock and the warm-up's size bound were held by no test, and a link at a temporary name of the process's pid stopped every warm-up (the blind review of 887abd8); the parse store moved out of every project into the user's cache, its segments written once and never changed (d-d1229127), so only the project's source files, which every reading reads, remain the repository's to shape + refuted: honored a warm-up lock stamped in the future (ParseStore.lock in src/plugins/syntax-trees.ts) -> "a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said" went red in syntax-trees.test.ts on its own assertion (the warm-up reads every text, unheld by the lock); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: let a failed rewrite throw out of the warm-up, as the folder named as the store's file made it before (ParseStore.rewrite in src/plugins/syntax-trees.ts) -> "a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said" went red in syntax-trees.test.ts with the warm-up's throw, the failure the bullet guards; restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: said an audit.json without checking this machine's signature (staleParsesNotice in src/plugins/syntax-trees.ts) -> "a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said" went red in syntax-trees.test.ts on its own assertion (an unsigned in-bounds audit was said); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: let a folder or a link at the lock's path hold the warm-up off (ParseStore.lock in src/plugins/syntax-trees.ts) -> "a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said" went red in syntax-trees.test.ts on its own assertion (a folder at the lock's path holds no warm-up off); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: measured a tree's errors by recursion (errorSpan in src/plugins/syntax-trees.ts) -> "a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said" went red in syntax-trees.test.ts on its own assertion (Maximum call stack size exceeded, where a file nested deep around an error is read); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: left a lock no warm-up can read in place (ParseStore.lock in src/plugins/syntax-trees.ts) -> "a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said" went red in syntax-trees.test.ts on its own assertion (a lock no warm-up can read holds no warm-up off); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: opened a project's source files following links, still without waiting on a pipe (warmText in src/economy/warm-parses.ts) -> "a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said" went red in syntax-trees.test.ts on its own assertion (the warm-up reads the project's own file alone, and finishes); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: took a dead lock over without the taking-over lock (ParseStore.takeOver in src/plugins/syntax-trees.ts, the review's t4) -> "a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said" went red in syntax-trees.test.ts on its own assertion (a dead lock another is taking over is left to it); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: read a source file of any size in the warm-up (warmText in src/economy/warm-parses.ts, the review's t5) -> "a repository's own files cannot stop a warm-up or speak at a session start: a folder where the store's file goes keeps no parses and the warm-up goes on, a lock stamped in the future or one no warm-up can read is taken over, a source file nested deep around an error is read, a source file that links out or to a pipe is never read, and an audit the project brings is never said" went red in syntax-trees.test.ts on its own assertion (the warm-up reads the project's own regular file alone, never one past 16 MB, and finishes); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: read a file whatever folder its path passes through (warmText in src/economy/warm-parses.ts) -> "a repository's own files cannot stop a warm-up: a source file nested deep around an error is read, and a source file that links out of the project, to a pipe, or past 16 MB is never read by the warm-up, which finishes" went red in syntax-trees.test.ts on its own assertion (the warm-up reads the project's own regular file alone); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a long-lived process reads what other processes did: A reading holds no kept parse in memory past the last few texts it read, and reads each from its own file when it is asked: a parse another process keeps is read at once, one another process removes (a stale store discarded) answers no more and the text is parsed again, and each parse is kept as it is made, so a process that parses and exits has kept everything it parsed with no step at its exit. Nothing is ever merged, reloaded or locked, and the memory of a process that lives long (the warm server, hook-serve) holds no store. + over: a reader in this process reading forty texts another process kept; another process's warm-up finding the store stale and removing it, then a text read before read again; and a process that parses three texts and exits + via: a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made + because: a process's own append restamped the store it had loaded, so a discard by another process in the same second went unseen and the warm server kept reading parses its audit had found stale; a pipe at the log's path hung the process at its append; and an empty key file made every process sign with a key of its own (the blind review of 45d4538); a discard left a store with no generation (the blind review of ca263d3); flush loaded the whole store and log at every short process's exit (the blind review of 887abd8); a key planted in a shared temporary folder signed what the planter wrote (the blind review of the fixes to 887abd8); the parse store moved into the user's cache in segments written once (d-d1229127), and then a long-lived reader held every segment it read in memory, 40 MB of kept parses at PostHog's scale, and read the whole store again after any other warm-up's merge (the blind review of 2558929); the parse store keeps each parse as a file of its own, written once, as git keeps a loose object (d-a5c35add): with no store in memory there is nothing to reload, and no segment to merge + refuted: kept every text's parse a reading met in memory, unbounded (readerOver in src/plugins/syntax-trees.ts) -> "a reading holds no kept parse past its last few texts and reads each from its own file: one another process keeps is read at once, one another removes answers no more, and each parse is kept as it is made" went red in syntax-trees.test.ts on its own assertion (and the text is parsed again); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- the parse store is reached only inside its module: syntax-trees.ts exports the readings (treeReaderOf, importShapes, capturesStatements, keptParseOf), the warm-up (warmParses), the fingerprint (fingerprintOf, KEPT_FROM), the notices (staleParsesNotice, parserNotice), the runtime's start and the capture names, and nothing that gives the store, its folder or a path; parsesFolder, the one place the store's path is made, builds on the user's cache (userCacheDir). + protects: parsesFolder in src/plugins/syntax-trees.ts + chokepoint: ParseStore in src/plugins/syntax-trees.ts + over: the names the module exports, as an import of it reads them + via: syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path + because: the parse-based tests that held every file call of the store to one gateway were beaten by ordinary spellings in three blind reviews, and gave way to what the compiler holds (d-d1229127); exporting parsesFolder through export { } then passed the text match that stood in for it (the blind review of 2558929), where an import of the module reads its exports as they are; the parse store keeps each parse as a file of its own, written once, as git keeps a loose object (d-a5c35add) + refuted: exported parsesFolder through export { } (src/plugins/syntax-trees.ts) -> "syntax-trees.ts gives out no way to the store: its exports are the readings, the warm-up, the fingerprint and the notice, never the store, its folder or a path" went red in syntax-trees.test.ts on its own assertion (the module's exports, parsesFolder among them); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a kept parse no process reads is swept: A warm-up sweeps the user's parse store at most once a day (the swept file's time): across every fingerprint it removes each kept parse no process has read in fourteen days, each temporary file a write that died left an hour on, each store a discard renamed away, and each folder that empties, so a fingerprint no Coherence reads any more goes with its last parse; a kept parse read is stamped as read when its last stamp is a day old, so one still read is kept, by whichever process reads it, and one whose time cannot be stamped is read all the same; a swept file dated ahead of now is no sweep; and the temporary files of writes that died are swept wherever the store writes whole, beside the swept file and among the audits and notes as in a shard. + over: ten kept parses aged thirty days, five of them read again by a reading that is no warm-up; a temporary file two hours old and one just made; another fingerprint's folder whose one parse is twenty days old; a store a discard left; a warm-up after the last sweep's day, and another within the day; a sweep dated a year ahead; temporary files two hours old beside the swept file and among the audits; and on macOS a kept parse made immutable with chflags + via: a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept + because: a merge kept what any segment written in fourteen days held, and every merge wrote a segment of now, so a parse no process read was carried forward for good; a merge kept a parse by the segment it was first read from, so one written again today was dropped when an older segment held it first; and a merge killed midway left its temporary file for ever (the blind review of 2558929); the parse store keeps each parse as a file of its own, written once, as git keeps a loose object (d-a5c35add): a parse's own file's time says when it was last read, so its age is its own; a swept file dated ahead stopped every sweep until that date, the temporary files beside the swept file and the audits were never swept, and a kept parse whose time could not be stamped was parsed again at every reading (the blind review of 766fba1) + refuted: stamped no kept parse as read (ownFile in src/plugins/syntax-trees.ts) -> "a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept" went red in syntax-trees.test.ts on its own assertion (one read since is kept); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: swept at every warm-up, whatever the last sweep's time (ParseStore.sweep in src/plugins/syntax-trees.ts) -> "a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept" went red in syntax-trees.test.ts on its own assertion (a warm-up within a day of a sweep sweeps nothing); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: swept a write's temporary file at once, however young (ParseStore.sweep in src/plugins/syntax-trees.ts) -> "a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept" went red in syntax-trees.test.ts on its own assertion (a write's temporary file is swept an hour on, never sooner); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: took a sweep dated ahead as one within the day (ParseStore.sweep in src/plugins/syntax-trees.ts) -> "a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept" went red in syntax-trees.test.ts on its own assertion (a warm-up after a sweep dated ahead sweeps); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: swept temporary files in shards alone (ParseStore.sweep in src/plugins/syntax-trees.ts) -> "a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept" went red in syntax-trees.test.ts on its own assertion (and the temporary files beside the swept file and among the audits); restored from a copy, byte for byte, green batched and alone (2026-10-27) + refuted: let a stamp that cannot be written fail the read (ownFile in src/plugins/syntax-trees.ts) -> "a kept parse no process has read in fourteen days is swept by a warm-up, at most once a day, with the temporary files of writes that died, a store a discard left and another fingerprint's folder; one read since is kept" went red in syntax-trees.test.ts on its own assertion (a kept parse that cannot be stamped is read, not parsed again); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- two warm-ups at once need no lock: Two warm-ups of one project at once both read every text and keep each text's parse once, whole and as a fresh parse reads it, with no temporary file left: each parse is written whole under a name of its own and renamed into place, so neither can spoil the other's; each warm-up reads the project's files in an order of its own, so two at once mostly parse different files, each reading what the other has kept by then. + over: two processes warming three hundred Python texts of one project at once, from an empty cache + via: two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it + because: the warm-up lock's taking over of a dead lock let several warm-ups of one project run at once, eight of eight in one round, and two merges at once dropped each other's segments (the blind review of 2558929); a lock that keeps the parse work from being done twice is a cost, and a store no two writers can spoil needs none; the parse store keeps each parse as a file of its own, written once, as git keeps a loose object (d-a5c35add) + refuted: held a second warm-up off while one runs, as the warm-up lock did (warmParses in src/plugins/syntax-trees.ts) -> "two warm-ups of one project at once both read every text, need no lock, and keep each text's parse once, whole and as a fresh parse reads it" went red in syntax-trees.test.ts on its own assertion (each reads every text); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a whole-module import reaches a reference name only where the importer spells it: A relation of the reference project that names what render imports holds where an import names each name, or where a whole-module import joins the file and render's text spells the name; a whole-module import alone reaches no name the importer never uses. + over: a plugin by path whose render imports the secrets module whole and never uses its names, and the same with render using them through the module + via: a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them + because: a blind review of the reference reading found one whole-module import satisfied every named relation, so Python's and Rust's check projects held the relations whatever their named-import readers did + refuted: let a whole-module import reach every name whether the importer spells it or not, as before (src/plugins/check.ts referenceRelations) -> "a whole-module import reaches a name of the reference project only where the importer spells it: an import of the secrets module whose names render never uses holds no relation to them" went red in reference.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- a plugin is never failed by a duty newer than its interface: plugin check holds the reference reading and server agrees duties from pluginApi 3, the version that brought what they ask (a reference map, topLevelSymbols); a plugin written for an older version passes each with a reason saying it is not held, from which version it would be, and what of that version the duty asks, never another change the version brought; and a plugin written for 3 whose adapter offers no topLevelSymbols fails server agrees. + over: a plugin by path written for pluginApi 2 whose adapter cannot be built, and the same plugin written for pluginApi 3 + via: a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3 + because: a blind review found every third-party plugin written before the new duties failing plugin check (server agrees read not run, which fails the command), against docs that called topLevelSymbols optional, while the interface version stayed 2; the reference reading's reason then quoted pluginApi 3's parser-path change rather than the reference map it asks (d-d2d20380) + refuted: held every plugin to the reference reading and server agrees whatever pluginApi it is written for (src/plugins/check.ts notHeld) -> "a plugin written for an older interface version is told a duty newer than it is not held, and never failed by it: reference reading and server agrees hold from pluginApi 3" went red in reference.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26); later, quoted pluginApi 3's parser-path change for every duty again -> red on the reference reading's reason not naming the reference map; restored (cmp), green batched and alone (2026-10-27) + kinds: none +- a TypeScript re-export is an import of what it re-exports: TypeScript's source scan reads export { a, b as c, type T } from "m", export * from "m" and export * as n from "m" each as an import of m, by the original name or whole, so a barrel file reaches every module it re-exports from in mass and the economy's closure. + over: a barrel index.ts re-exporting from three modules by name, renamed, type-only, whole, and whole under a namespace + via: a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace + because: the answers agree duty, on a blind reviewer's probe, found TypeScript's interfaces slot listing a renamed re-export the source scan read no import of: the scan read import statements alone, so a barrel file's dependencies were invisible to mass and the closure + refuted: made the source scan read no re-export, as before (plugins/typescript/typescript-source.ts) -> "a TypeScript re-export is read as an import of the module it re-exports from: by name, renamed, type-only, whole, and whole under a namespace" went red in typescript-reexports.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- the plugin guide's tables list what the code holds: docs/plugins.md's duty, manifest key, syntax slot, treeSitter key, capture and adapter method tables each list exactly the names the code holds (LANGUAGE_DUTIES, MANIFEST_KEYS, SYNTAX_SLOTS, TREE_SITTER_KEYS, CAPTURES, ADAPTER_METHODS), and MANIFEST_KEYS, TREE_SITTER_KEYS and ADAPTER_METHODS fail to compile when their type gains a member they lack. + over: every row of the six tables, against each list + via: docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods + because: the guide's manifest table lacked basisFiles and moduleFolders and named provides.language for provides, and its capture table lacked @import, each found the first time the tables were held to the code; mnemion's Swift plugin was written from a guide that had drifted from what the bundled plugins did + refuted: dropped the server agrees row from the guide's duty table (docs/plugins.md) -> "docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods" went red in plugin-docs.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- the plugin guide's examples validate: every plugin.json example in docs/plugins.md is written for the interface version this Coherence runs and validates as a manifest, and every treeSitter example names only treeSitter's keys. + over: every json block of docs/plugins.md that carries a pluginApi, and every one that opens with treeSitter + via: every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys + because: the 1.11.0-beta.0 guide's manifest example still showed pluginApi 2 with hand-written slots while the interface moved on, and mnemion's plugin was written from it + refuted: set the guide's manifest example back to pluginApi 2, as the 1.11.0-beta.0 guide had it (docs/plugins.md) -> "every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys" went red in plugin-docs.test.ts on its own assertion; restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none +- the plugin guide's claims are true of the bundled plugins: each bundled plugin docs/plugins.md marks as read through a parser names one in its manifest, a claim of any other kind fails, since a plugin reads its text through a parser or not at all, and the plugin the guide says to start from reads through a parser. + over: every claims marker in docs/plugins.md and its start-from sentence, against each bundled manifest + via: docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, and the plugin it says to start from reads through a parser + because: the 1.11.0-beta.0 guide told an author writing a plugin for a language Coherence lacks to start from go, which reads by hand, after Python had moved to a parser, and mnemion's Swift plugin was written by hand from it; a statement about the bundle is a fact about the code and is held as one + refuted: marked go hand-written in the guide's claims, though it reads through a parser (docs/plugins.md) -> "docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, each named hand-written fills its source slot by hand, and the plugin it says to start from reads through a parser" (the test's title then) went red in plugin-docs.test.ts on its own assertion (the guide says go reads its text by hand; its manifest names a parser); the earlier refutation, the guide saying to start from go, no longer reds since go reads through a parser (the blind review of 413b9a6); restored from a copy, byte for byte, green batched and alone (2026-10-27) + kinds: none +- a registry's leaves share one parse store: The leaves of a registry and its top share the user's one parse store, as every project does: a warm-up of a leaf pre-reads the leaf's files and the top's, and a warm-up of another leaf reads what the first kept; no project keeps a store of its own. + over: a registry of two leaves and a folder outside both, warmed from one leaf, then from the other + via: a registry's leaves and its top share the user's one parse store: a warm-up of one leaf pre-reads the leaf and the top's files, and a warm-up of another reads what the first kept + because: on PostHog's registry each leaf's warm-up kept its own store, so mass and status at the repository's top parsed every file again (16.4 s against main's 3.9 s) and their appends grew a 30 MB log nothing folded in; shared at the top, mass there after a warm-up takes 3.6 s; the parse store moved out of every project into the user's cache, its segments written once and never changed (d-d1229127), and storeRootOf with it + refuted: kept each project's parses at its own root, as before (src/plugins/languages.ts storeRootOf) -> "a registry's leaves share one parse store at the repository's top: a warm-up of one leaf keeps what another leaf's read, and pre-reads the top's files" went red in syntax-trees.test.ts on its own assertion (no leaf keeps a store of its own); restored from a copy, byte for byte; made a warm-up's rewrite keep only what that pass read (src/plugins/syntax-trees.ts rewrite) -> the same test went red on its own assertion (b's warm-up keeps a's and the top's); restored from a copy, byte for byte, green batched and alone (2026-10-26) + kinds: none diff --git a/src/plugins/answers-agree.test.ts b/src/plugins/answers-agree.test.ts new file mode 100644 index 00000000..246dc68a --- /dev/null +++ b/src/plugins/answers-agree.test.ts @@ -0,0 +1,81 @@ +/** + * plugin check's "answers agree" duty: two readings that answer one question + * of the same text are run over the check project and held to agree, so a + * reader that misses what another reads is caught on the plugin's own + * project (df-7ac38ee4, Python's two hand-written import readers). The + * parser derives every reading of the text from one parse, and a plugin's + * interfaces table states no reading of it (languages.ts statedFacts), so + * what the duty still finds is queries that read a declaration by what + * surrounds it, which the same queries over its line alone read otherwise. + */ + +import assert from "node:assert/strict"; +import { mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { after, test } from "node:test"; +import { checkPlugin } from "./check.ts"; +import { writeParserPlugin } from "./fixtures/parser-plugin.ts"; +import { BUNDLED_DIR } from "./registry.ts"; + +const fixtures: string[] = []; +after(() => { + for (const dir of fixtures) rmSync(dir, { recursive: true, force: true }); +}); + +/** A stand-in server that reports, of each file, the top-level symbols given. */ +function standIn(symbols: Record): string { + return `const SYMBOLS = ${JSON.stringify(symbols)};\nexport default { adapter: ({ language }) => ({ language, ladder: { top: "reference-choked", because: "a stand-in", rungs: [] }, ready: async () => ({ ok: true }), topLevelSymbols: async (file) => (SYMBOLS[file] ?? []).map((name) => ({ name, line: 1, kind: 12 })), resolve: async () => ({ ok: false, reason: "a stand-in" }), references: async () => [], visibility: async () => ({ enforced: false, visible: true, evidence: "a stand-in" }), testFilter: (via) => via, refute: async () => ({ seen: false, staged: [], account: "a stand-in" }), forget: async () => {}, close: async () => {} }) };\n`; +} + +const SECRETS = "SECRET_COLUMNS = []\n\ndef seal(row):\n return row\n"; + +/** Python's queries, as the bundled plugin reads Python. */ +const PYTHON_QUERIES = readFileSync(join(BUNDLED_DIR, "python", "python.scm"), "utf8"); +const DECORATED = "(module (decorated_definition definition: [(function_definition name: (identifier) @name) (class_definition name: (identifier) @name)]) @declaration.body)"; + +/** A plugin by path reading zz through Python's parser and the queries given, its interfaces table's facts, its server and its check project's render file as given. */ +function parserPlugin(render: string, queries: string, symbols: Record): string { + const root = mkdtempSync(join(tmpdir(), "coherence-answers-agree-")); + fixtures.push(root); + writeParserPlugin(join(root, "zz"), { syntax: { interfaces: "facts.ts#FACTS" } }, { + "index.ts": standIn(symbols), + "zz.scm": queries, + "facts.ts": "export const FACTS = { serverBounds: false };\n", + "check.json": JSON.stringify({ + files: { "api/render.zz": render, "store/secrets.zz": SECRETS }, + language: { files: ["api/render.zz", "store/secrets.zz"], not: [] }, + declarations: [{ file: "store/secrets.zz", name: "seal", declared: true }], + protects: "SECRET_COLUMNS", chokepoint: "seal", references: [], grade: "reference-choked", bypasses: [], + }), + }); + return root; +} + +const RENDER = "from store.secrets import SECRET_COLUMNS, seal as sealed\n\n@dataclass\nclass Row:\n pass\n\ndef render(row):\n return sealed(row)\n"; +const EVERY_SYMBOL = { "store/secrets.zz": ["SECRET_COLUMNS", "seal"], "api/render.zz": ["Row", "render"] }; + +test("plugin check fails a plugin whose two readings of one text disagree: queries that read a declaration's kind from what surrounds it, so its line read alone says otherwise, named by file and name", async () => { + // A decorated class declares a type, and an undecorated one a body: the whole text reads Row as a type, its line alone as a body. + assert.ok(PYTHON_QUERIES.includes(DECORATED), "the queries the test changes are Python's"); + const contextual = PYTHON_QUERIES.replace(DECORATED, "(module (decorated_definition definition: (function_definition name: (identifier) @name)) @declaration.body)\n(module (decorated_definition definition: (class_definition name: (identifier) @name)) @declaration.type)"); + const split = parserPlugin(RENDER, contextual, EVERY_SYMBOL); + const failed = (await checkPlugin(split, "./zz")).duties.find((d) => d.name === "answers agree")!; + assert.equal(failed.verdict, "fail", failed.reason); + assert.match(failed.reason, /api\/render\.zz:4: interfaces reads Row's line as no type declaration, declares as type/); + assert.doesNotMatch(failed.reason, /render\.zz:7|secrets\.zz/, "a line both read alike is no failure"); + + // Python's own queries read a decorated class as its line alone reads it, and the answers agree. + const agreeing = parserPlugin(RENDER, PYTHON_QUERIES, EVERY_SYMBOL); + const agreed = (await checkPlugin(agreeing, "./zz")).duties.find((d) => d.name === "answers agree")!; + assert.equal(agreed.verdict, "pass", agreed.reason); +}); + +test("plugin check fails a plugin whose text reading declares a name the language server reports no top-level symbol of, named by file and line", async () => { + // The parser declares render; a server whose account lacks it reports no such symbol. + const misread = parserPlugin(RENDER, PYTHON_QUERIES, { "store/secrets.zz": ["SECRET_COLUMNS", "seal"], "api/render.zz": ["Row"] }); + const failed = (await checkPlugin(misread, "./zz")).duties.find((d) => d.name === "server agrees")!; + assert.equal(failed.verdict, "fail", failed.reason); + assert.match(failed.reason, /api\/render\.zz:7: the text reading declares render, which the language server reports no top-level symbol of/); + assert.doesNotMatch(failed.reason, /declares (Row|seal|SECRET_COLUMNS)\b/, "a name the server reports is no failure"); +}); diff --git a/src/plugins/api.ts b/src/plugins/api.ts index fdf9d7a2..f526f295 100644 --- a/src/plugins/api.ts +++ b/src/plugins/api.ts @@ -25,6 +25,7 @@ export { type Definition, type Ladder, type LanguageAdapter, + type ServerSymbol, type Occasion, type Position, type Range, @@ -45,12 +46,13 @@ export { languageOfFile } from "../adapters/language-files.ts"; export { fileIdentity, horizonFolders, keepHorizonFiles, keepProjectFiles, nestedCheckouts, nestedFolder, neverWalkedName, projectListing, repositoryTop, walkBounds, walkedProjectFiles, type ProjectListing } from "../adapters/project-files.ts"; // TOML's line lookup is exported under its own name: entrance detection has a lineOf of its own. export { lineOf as tomlLineOf, parseToml, TomlError, type TomlTable, type TomlValue } from "../adapters/toml.ts"; -export { isSourceFile, toRelative, type SourceSyntax } from "../economy/source.ts"; +export { isSourceFile, toRelative, type ImportTarget } from "../economy/source.ts"; export { configRecord } from "../adapters/project-config.ts"; export { killTree } from "../enforcement/totality.ts"; +export type { Literal } from "../lifecycle/mirrors.ts"; export { spawn, spawnSync } from "../lifecycle/work-meter.ts"; export { typescriptCompiler } from "./specifiers.ts"; export type { InterfaceSymbol } from "../observation/interfaces.ts"; -export type { InterfaceSyntax } from "../readings/scope/component-interfaces.ts"; +export type { InterfaceFacts } from "../readings/scope/component-interfaces.ts"; export { readOwners, type BoundaryModule, type BoundarySource, type Exposure } from "../scaffold/boundaries.ts"; export { ScaffoldError } from "../scaffold/scaffold.ts"; diff --git a/src/plugins/calibrate.test.ts b/src/plugins/calibrate.test.ts new file mode 100644 index 00000000..d68c4d7d --- /dev/null +++ b/src/plugins/calibrate.test.ts @@ -0,0 +1,41 @@ +/** + * coherence plugin calibrate: the text reading's declarations against the + * language server's top-level symbols over a real project, misreads named + * and what the server alone reports counted by kind. + */ + +import assert from "node:assert/strict"; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join } from "node:path"; +import { after, test } from "node:test"; +import { calibrate, calibrationText } from "./calibrate.ts"; +import { writeParserPlugin } from "./fixtures/parser-plugin.ts"; + +const fixtures: string[] = []; +after(() => { + for (const dir of fixtures) rmSync(dir, { recursive: true, force: true }); +}); + +test("plugin calibrate names each declaration the text reading finds that the language server reports no top-level symbol of, and counts what the server alone reports by kind", async () => { + const root = mkdtempSync(join(tmpdir(), "coherence-calibrate-")); + fixtures.push(root); + // Read through Python's parser, which declares TEMPLATE and render and binds helper without declaring it. + writeParserPlugin(join(root, "zz"), {}, { + // A server whose account differs from the parse: it knows no render, which the reading declares, and reports a lowercase variable the reading leaves out. + "index.ts": 'const SYMBOLS = { "app/render.zz": [["TEMPLATE", 13], ["helper", 13]] };\nexport default { adapter: ({ language }) => ({ language, ladder: { top: "reference-choked", because: "a stand-in", rungs: [] }, ready: async () => ({ ok: true }), topLevelSymbols: async (file) => (SYMBOLS[file] ?? []).map(([name, kind]) => ({ name, line: 1, kind })), resolve: async () => ({ ok: false, reason: "a stand-in" }), references: async () => [], visibility: async () => ({ enforced: false, visible: true, evidence: "a stand-in" }), testFilter: (via) => via, refute: async () => ({ seen: false, staged: [], account: "a stand-in" }), forget: async () => {}, close: async () => {} }) };\n', + }); + const files: Record = { + "coherence.config.json": JSON.stringify({ language: "zz", plugins: { zz: "./zz" } }), + "app/render.zz": ["TEMPLATE = '''", "class Fake:", " pass", "'''", "helper = 1", "", "def render(row):", " return row", ""].join("\n"), + }; + for (const [path, text] of Object.entries(files)) { + mkdirSync(dirname(join(root, path)), { recursive: true }); + writeFileSync(join(root, path), text); + } + const [zz] = await calibrate(root); + assert.ok(zz !== undefined && !("notRun" in zz), JSON.stringify(zz)); + assert.deepEqual({ declared: zz.declared, agreed: zz.agreed, readerOnly: zz.readerOnly }, { declared: 2, agreed: 1, readerOnly: ["app/render.zz:7 render"] }); + assert.deepEqual(zz.serverOnly, [{ kind: "variable", count: 1, example: "app/render.zz:1 helper" }]); + assert.match(calibrationText([zz]), /MISREAD 1 the reading declares and the server reports no top-level symbol of/); +}); diff --git a/src/plugins/calibrate.ts b/src/plugins/calibrate.ts new file mode 100644 index 00000000..f90e9152 --- /dev/null +++ b/src/plugins/calibrate.ts @@ -0,0 +1,117 @@ +/** + * coherence plugin calibrate: the text reading's declarations held to the + * language server's own account of each file, over a real project. The text + * readings are Coherence's instruments (mass, the economy, the interface + * reading count by them), and an instrument is calibrated against an + * independent reference: here the server the language's adapter drives. + * + * Two counts, never one verdict. A name the reading finds and the server + * does not is a misread (a name read out of a string or a comment). A name + * the server reports and the reading leaves out is counted by its symbol kind, + * since a reading may leave a kind out by design (Python's lowercase module + * variables), and a kind left out wholesale shows which. + * + * Advisory: a reading, it fails nothing. Its languages' servers are started + * as a run starts them, so it costs what the server costs to load. + */ + +import { readFileSync } from "node:fs"; +import { join, resolve } from "node:path"; +import type { LanguageAdapter } from "../adapters/adapter.ts"; +import { configIgnore } from "../adapters/project-files.ts"; +import { declarationsOf, sourceFiles } from "../economy/source.ts"; +import { readEnforcementConfig } from "../enforcement/config.ts"; +import { coreAdapter, forProject } from "./languages.ts"; + +/** LSP SymbolKind names, by number. */ +const KINDS: Record = { 1: "file", 2: "module", 3: "namespace", 4: "package", 5: "class", 6: "method", 7: "property", 8: "field", 9: "constructor", 10: "enum", 11: "interface", 12: "function", 13: "variable", 14: "constant", 15: "string", 16: "number", 17: "boolean", 18: "array", 19: "object", 20: "key", 21: "null", 22: "enum member", 23: "struct", 24: "event", 25: "operator", 26: "type parameter" }; + +/** One language's calibration, or why it was not taken. */ +export type Calibration = + | { language: string; files: number; declared: number; agreed: number; readerOnly: string[]; readerOnlyCount: number; serverOnly: { kind: string; count: number; example: string }[] } + | { language: string; notRun: string }; + +/** The calibration of each language the project reads, over its first `limit` source files in path order. */ +export async function calibrate(rootGiven: string, limit = 200): Promise { + const root = resolve(rootGiven); + const config = readEnforcementConfig(root); + const ignore = configIgnore(root); + const out: Calibration[] = []; + for (const language of config.languages) { + out.push( + await forProject(root, async (): Promise => { + let adapter: LanguageAdapter | undefined; + try { + adapter = coreAdapter(language, root); + } catch (error) { + return { language, notRun: `its adapter could not be built: ${error instanceof Error ? error.message : String(error)}` }; + } + if (adapter === undefined) return { language, notRun: "no plugin's adapter answers for it" }; + try { + if (adapter.topLevelSymbols === undefined) return { language, notRun: "its adapter offers no topLevelSymbols to calibrate against" }; + const ready = await adapter.ready(); + if (!ready.ok) return { language, notRun: `its language server is not up: ${ready.reason}` }; + const files = sourceFiles(root, language, ignore).slice(0, limit); + let declared = 0; + let agreed = 0; + const readerOnly: string[] = []; + let readerOnlyCount = 0; + const serverOnly = new Map(); + for (const file of files) { + let text: string; + try { + text = readFileSync(join(root, file), "utf8"); + } catch { + continue; + } + const read = declarationsOf(text, language); + const symbols = await adapter.topLevelSymbols(file); + const named = new Set(symbols.map((s) => s.name)); + const reading = new Set(read.map((d) => d.name)); + for (const d of read) { + declared++; + if (named.has(d.name)) agreed++; + else { + readerOnlyCount++; + if (readerOnly.length < 10) readerOnly.push(`${file}:${d.line} ${d.name}`); + } + } + for (const s of symbols) { + if (reading.has(s.name)) continue; + const kind = KINDS[s.kind] ?? `kind ${s.kind}`; + const known = serverOnly.get(kind) ?? { count: 0, example: `${file}:${s.line} ${s.name}` }; + known.count++; + serverOnly.set(kind, known); + } + } + return { language, files: files.length, declared, agreed, readerOnly, readerOnlyCount, serverOnly: [...serverOnly].map(([kind, v]) => ({ kind, ...v })).sort((a, b) => b.count - a.count) }; + } finally { + await adapter.close(); + } + }), + ); + } + return out; +} + +/** The calibration as the command prints it. */ +export function calibrationText(calibrations: readonly Calibration[]): string { + const lines: string[] = []; + for (const c of calibrations) { + if ("notRun" in c) { + lines.push(`${c.language}: not run: ${c.notRun}`); + continue; + } + lines.push(`${c.language}: ${c.files} files, the text reading's ${c.declared} declarations against the language server's top-level symbols`); + lines.push(` ${c.agreed} of ${c.declared} the server reports too`); + if (c.readerOnlyCount > 0) { + lines.push(` MISREAD ${c.readerOnlyCount} the reading declares and the server reports no top-level symbol of: a name read from a string, a comment or another scope${c.readerOnlyCount > c.readerOnly.length ? `; the first ${c.readerOnly.length}` : ""}:`); + for (const r of c.readerOnly) lines.push(` ${r}`); + } + if (c.serverOnly.length > 0) { + lines.push(" the server reports, the reading leaves out (by design, or missed), by kind:"); + for (const s of c.serverOnly) lines.push(` ${String(s.count).padStart(6)} ${s.kind.padEnd(14)} e.g. ${s.example}`); + } + } + return lines.join("\n"); +} diff --git a/src/plugins/check.ts b/src/plugins/check.ts index f714975a..905b0baa 100644 --- a/src/plugins/check.ts +++ b/src/plugins/check.ts @@ -5,14 +5,22 @@ * * file rule the files check.json names as the language's are, and * those it names as not are not - * declarations the topLevel slot says which names a file's top level - * declares + * declarations the parser's topLevel reading says which names a file's + * top level declares * references the adapter reports every reference to the protected * thing, and none else; a plugin that reports none fails * here, by name + * reference reading the readings recover, over the check project, every + * relation of the reference project (REFERENCE) its map + * places there, as every language's plugin must + * server agrees every name the text reading finds a file declaring is a + * top-level symbol the language server reports for it * chokepoint the check grades the protected thing through the * chokepoint as check.json expects, bypasses named, its * refutation seen or refused, never missing + * answers agree where two of its readings answer one question of the + * same text (a declaration, a renamed import), their + * answers agree over every file of the check project * one answer each no two of its slots answer with one function, or two * spelled alike: a question asked of the language belongs * to one slot, or its answers drift apart @@ -44,12 +52,12 @@ import { tmpdir } from "node:os"; import { dirname, isAbsolute, join, resolve } from "node:path"; import type { LanguageAdapter } from "../adapters/adapter.ts"; import { computeMass } from "../economy/mass.ts"; -import { declarationsOf, importsOf } from "../economy/source.ts"; +import { declarationsOf, importsOf, isSourceFile } from "../economy/source.ts"; import { DEFAULT_TEST_FOLDERS } from "../enforcement/config.ts"; import { performRun } from "../enforcement/run.ts"; import { detectedEntrances, readComponentInterfaces } from "../readings/scope/component-interfaces.ts"; -import { bundledAdapter, bundledPlugins, forProject, languageOfFile, registerProjectPlugins, repeatedAnswers, syntaxOf } from "./languages.ts"; -import type { LoadedPlugin } from "./plugin.ts"; +import { bundledAdapter, bundledPlugins, forProject, languageOfFile, parsedOf, registerProjectPlugins, repeatedAnswers } from "./languages.ts"; +import { DUTY_SINCE, type LoadedPlugin } from "./plugin.ts"; import { BUNDLED_DIR, moduleSyncOf, readManifest } from "./registry.ts"; import { proveVia, viaForm } from "./verify.ts"; @@ -70,6 +78,146 @@ export interface CheckProject { bypasses: string[]; /** What each reading that scans the language's text must recover over the project; the bundled minimum for a language carries it. */ readings?: Readings; + /** Which of the project's files and names play each part of the reference project every language plugin is held to read alike (REFERENCE). */ + reference?: ReferenceMap; +} + +/** A check project's map onto the reference project: the file playing each role, and the language's spelling of each name. */ +export interface ReferenceMap { + files: Record; + names: Record; +} + +/** + * The reference project, the same in every language: a store module of two + * files (secrets declaring SECRET_COLUMNS and seal, rows declaring Row), a + * render that uses all three, and an entry (main) that uses render. Every + * language plugin's check project maps its files and names onto these, and + * its readings must recover the same relations, so two plugins cannot read + * the same shape of project two ways: four plugins picked the file a module + * import reaches four ways, and each missed one of a two-file module's files + * (d-cb7829df). + */ +export const REFERENCE_ROLES = ["secrets", "rows", "render", "main"] as const; +export type ReferenceRole = (typeof REFERENCE_ROLES)[number]; +export const REFERENCE_NAMES = ["SECRET_COLUMNS", "seal", "Row", "render"] as const; +export type ReferenceName = (typeof REFERENCE_NAMES)[number]; +const REFERENCE: { declared: [ReferenceRole, ReferenceName[]][]; imports: [ReferenceRole, ReferenceRole, ReferenceName[]][] } = { + declared: [ + ["secrets", ["SECRET_COLUMNS", "seal"]], + ["rows", ["Row"]], + ["render", ["render"]], + ], + imports: [ + ["render", "secrets", ["SECRET_COLUMNS", "seal"]], + ["render", "rows", ["Row"]], + ["main", "render", ["render"]], + ], +}; + +/** Each relation of the reference project a language's readings recover over its check project, said as one line, and each it does not, with why. */ +export function referenceRelations(scratch: string, project: CheckProject, map: ReferenceMap, language: string): { held: string[]; missed: string[] } { + const held: string[] = []; + const missed: string[] = []; + const name = (n: ReferenceName): string => map.names[n]; + for (const [role, names] of REFERENCE.declared) { + const file = map.files[role]; + const found = new Set(declarationsOf(project.files[file] ?? "", language).map((d) => d.name)); + const line = `${role} declares ${names.join(", ")}`; + const lacking = names.filter((n) => !found.has(name(n))); + (lacking.length === 0 ? held : missed).push(lacking.length === 0 ? line : `${line}: ${file} read declaring no ${lacking.map(name).join(", ")}`); + } + for (const [from, to, names] of REFERENCE.imports) { + const imports = importsOf(scratch, map.files[from], project.files[map.files[from]] ?? "", language).filter((i) => i.module === map.files[to]); + const reached = new Set(imports.map((i) => i.name ?? "*")); + const line = `${from} imports ${names.join(", ")} from ${to}`; + // A name is reached when an import names it, or when a whole-module import joins the file and the importer spells the name: + // a whole-module import alone reaches no name the importer never uses. + const text = project.files[map.files[from]] ?? ""; + const spelled = (n: string): boolean => new RegExp(`(? !reached.has(name(n)) && !(reached.has("*") && spelled(name(n)))); + if (imports.length === 0) missed.push(`${line}: ${map.files[from]} read importing nothing from ${map.files[to]}`); + else if (lacking.length > 0) missed.push(`${line}: ${map.files[from]} read importing no ${lacking.map(name).join(", ")} from ${map.files[to]}`); + else held.push(line); + } + return { held, missed }; +} + +const UNMAPPED = "nothing to check: the check project maps none of its files onto the reference project (reference), so nothing holds this plugin to read it as every language does"; + +/** One language plugin's reading of the reference project: each relation held or missed, or why it was not read. */ +export type ReferenceReading = { plugin: string; language: string; held: string[]; missed: string[] } | { plugin: string; language: string; notRead: string }; + +/** + * coherence plugin compare: every language plugin's reading of the + * reference project side by side, the bundled ones (opt-in among them) and + * any the project's config names, each over the check project that maps it, + * so a plugin that reads the same shape of project another way stands out. + */ +export async function compareReference(configured: readonly LoadedPlugin[] = []): Promise { + const bundled = readdirSync(BUNDLED_DIR) + .sort() + .flatMap((name): LoadedPlugin[] => { + const dir = join(BUNDLED_DIR, name); + if (!existsSync(join(dir, "plugin.json"))) return []; + const { manifest } = readManifest(name, dir, `bundled plugin ${name}`); + return manifest?.provides?.language === undefined ? [] : [{ name, version: manifest.version, dir, source: "bundled", manifest }]; + }); + const plugins = [...bundled, ...configured.filter((p) => p.manifest.provides?.language !== undefined && !bundled.some((b) => b.dir === p.dir))]; + const out: ReferenceReading[] = []; + for (const plugin of plugins) { + const language = plugin.manifest.provides!.language!; + const projects = checkProjects(plugin, language); + const mapped = "refusal" in projects ? undefined : [...projects].reverse().find((p) => p.project.reference !== undefined); + if (mapped === undefined) { + out.push({ plugin: plugin.name, language, notRead: "refusal" in projects ? projects.refusal : "no check project of it maps the reference project" }); + continue; + } + out.push({ plugin: plugin.name, language, ...(await inScratch(mapped.project, plugin, language, (scratch) => referenceRelations(scratch, mapped.project, mapped.project.reference!, language))) }); + } + return out; +} + +/** The comparison as the command prints it: each relation, and each plugin's mark for it. */ +export function compareText(readings: readonly ReferenceReading[]): string { + const read = readings.filter((r): r is Extract => "held" in r); + const relation = (line: string): string => line.split(": ")[0]!; + const relations = [...new Set(read.flatMap((r) => [...r.held, ...r.missed].map(relation)))]; + const width = Math.max(...relations.map((r) => r.length), 10); + const lines = [`the reference project, read by each language plugin over its check project`, ` ${"".padEnd(width)} ${read.map((r) => r.plugin).join(" ")}`]; + for (const rel of relations) lines.push(` ${rel.padEnd(width)} ${read.map((r) => (r.held.includes(rel) ? "yes" : r.missed.some((m) => relation(m) === rel) ? "NO" : "-").padEnd(r.plugin.length)).join(" ")}`); + for (const r of read) for (const m of r.missed) lines.push(`DIVERGES ${r.plugin} (${r.language}): ${m}`); + for (const r of readings) if ("notRead" in r) lines.push(`not read: ${r.plugin} (${r.language}): ${r.notRead}`); + return lines.join("\n"); +} + +/** A scratch copy of a check project with the plugin in its language's place, the work run for it, and the copy gone after. */ +export async function inScratch(project: CheckProject, plugin: LoadedPlugin, language: string, work: (scratch: string) => T | Promise): Promise { + const scratch = realpathSync(mkdtempSync(join(tmpdir(), "coherence-plugin-check-"))); + try { + for (const [path, text] of Object.entries(project.files)) { + mkdirSync(dirname(join(scratch, path)), { recursive: true }); + writeFileSync(join(scratch, path), text); + } + writeFileSync(join(scratch, CONFIG), JSON.stringify(checkConfig(project, plugin, language), null, 2) + "\n"); + registerProjectPlugins(scratch, isDefault(plugin) ? [] : [plugin]); + return await forProject(scratch, () => work(scratch)); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +/** + * reference reading: the language's readings recover, over its check project, + * every relation of the reference project its reference map places there. + */ +function referenceRead(scratch: string, project: CheckProject, plugin: LoadedPlugin, language: string): Duty { + const older = notHeld("reference reading", plugin); + if (older !== undefined) return older; + const map = project.reference; + if (map === undefined) return { name: "reference reading", verdict: "fail", reason: UNMAPPED }; + const { held, missed } = referenceRelations(scratch, project, map, language); + return missed.length === 0 ? { name: "reference reading", verdict: "pass", reason: `${held.length} of ${held.length} relations of the reference project read` } : { name: "reference reading", verdict: "fail", reason: missed.join("; ") }; } /** The answers the text readings must give over a check project, each compared exactly. */ @@ -91,7 +239,7 @@ type ReadingDuty = (typeof READING_DUTIES)[number]; /** One duty's outcome. */ export interface Duty { /** A language plugin's duties, or a verifier's one per form it declares, as a bullet writes it ("[quint run]"). */ - name: "file rule" | "declarations" | "references" | "chokepoint" | "one answer each" | ReadingDuty | `[${string}]`; + name: "file rule" | "declarations" | "answers agree" | "reference reading" | "references" | "server agrees" | "chokepoint" | "one answer each" | ReadingDuty | `[${string}]`; verdict: "pass" | "fail" | "not run"; reason: string; } @@ -151,13 +299,18 @@ export function checkProjectProblem(value: unknown): string | undefined { if (!each(readings["entrances"], ["file", "symbol", "rule"], [])) wrong.push('readings.entrances, a list of { "file", "symbol", "rule" }'); } } + const reference = value["reference"]; + if (reference !== undefined && !(record(reference) && record(reference["files"]) && record(reference["names"]) && REFERENCE_ROLES.every((r) => typeof (reference["files"] as Record)[r] === "string") && REFERENCE_NAMES.every((n) => typeof (reference["names"] as Record)[n] === "string"))) wrong.push(`reference, { "files": { ${REFERENCE_ROLES.map((r) => `"${r}"`).join(", ")} }, "names": { ${REFERENCE_NAMES.map((n) => `"${n}"`).join(", ")} } }`); return wrong.length === 0 ? undefined : `it lacks ${wrong.join("; ")}`; } -const DUTIES = ["file rule", "declarations", "references", "chokepoint"] as const; +const DUTIES = ["file rule", "declarations", "answers agree", "reference reading", "references", "server agrees", "chokepoint"] as const; + +/** Every duty plugin check holds a language plugin to, in the order it reports them: what docs/plugins.md's duty table must list. */ +export const LANGUAGE_DUTIES = [...DUTIES, ...READING_DUTIES, "one answer each"] as const; /** The check projects a plugin is held over: the minimum (the bundled plugin's check.json for its language, as the installed package ships it, which no copy edits) and, when it adds to that, the plugin's own. */ -function checkProjects(plugin: LoadedPlugin, language: string): { label: string; project: CheckProject }[] | { refusal: string } { +export function checkProjects(plugin: LoadedPlugin, language: string): { label: string; project: CheckProject }[] | { refusal: string } { const read = (file: string, label: string): CheckProject | string => { let value: unknown; try { @@ -244,8 +397,14 @@ async function languageDutiesOf(plugin: LoadedPlugin, language: string): Promise const worst = found.reduce((a, b) => (rank[b.verdict] > rank[a.verdict] ? b : a)); return { name, verdict: worst.verdict, reason: found.map((d) => d.reason).join("; ") }; }; + // The reference project is held over the check projects that map it: one that maps none (an extending plugin's own, beside the bundled minimum that does) says nothing, unless none maps it. + const unmapped = (d: Duty): boolean => d.name === "reference reading" && d.reason.includes(UNMAPPED); return [ - ...DUTIES.map((name) => worstOf(name, each.map((duties) => duties.find((d) => d.name === name)!))), + ...DUTIES.map((name) => { + const found = each.map((duties) => duties.find((d) => d.name === name)!); + const held = found.filter((d) => !unmapped(d)); + return worstOf(name, held.length > 0 ? held : found); + }), // A reading duty is held over every project that names what the readings recover; a plugin over none of them reads, for all anyone can tell, nothing. ...READING_DUTIES.map((name) => { const found = each.flatMap((duties) => duties.filter((d) => d.name === name)); @@ -258,7 +417,7 @@ async function languageDutiesOf(plugin: LoadedPlugin, language: string): Promise /** Whether each of the plugin's answers is given by one slot alone (repeatedAnswers). */ function oneAnswerEach(plugin: LoadedPlugin): Duty { const repeated = repeatedAnswers(plugin); - return repeated.length === 0 ? { name: "one answer each", verdict: "pass", reason: "no two slots give one answer" } : { name: "one answer each", verdict: "fail", reason: `${repeated.join("; ")}: keep the answer in one slot (the kept answers read interfaces.wildcardModules, so a kept slot that repeats it goes)` }; + return repeated.length === 0 ? { name: "one answer each", verdict: "pass", reason: "no two slots give one answer" } : { name: "one answer each", verdict: "fail", reason: `${repeated.join("; ")}: keep the answer in one slot` }; } /** A duty's outcome, or the duty failed with what it threw: one duty that throws never takes the others' outcomes with it. */ @@ -286,7 +445,7 @@ async function overProject(project: CheckProject, plugin: LoadedPlugin, language const readings = project.readings; // The plain scans read the scratch project before the adapter's duties write any spec into it. const scans = readings === undefined ? [] : [await guarded("mass", () => massRead(scratch, project, readings, language)), await guarded("imports", () => importsRead(scratch, project, readings, language)), await guarded("entrances", () => entrancesRead(scratch, readings, language))]; - return [await guarded("file rule", () => fileRule(project, language)), await guarded("declarations", () => declarations(project, language)), ...scans, ...(await instrument(scratch, project, plugin, language))]; + return [await guarded("file rule", () => fileRule(project, language)), await guarded("declarations", () => declarations(project, language)), await guarded("answers agree", () => answersAgree(project, language)), await guarded("reference reading", () => referenceRead(scratch, project, plugin, language)), ...scans, ...(await instrument(scratch, project, plugin, language))]; }); } finally { rmSync(scratch, { recursive: true, force: true }); @@ -305,12 +464,69 @@ function fileRule(project: CheckProject, language: string): Duty { function declarations(project: CheckProject, language: string): Duty { if (project.declarations.length === 0) return { name: "declarations", verdict: "fail", reason: "nothing to check: the check project names no declaration" }; - const topLevel = syntaxOf(language, "topLevel"); - if (topLevel === undefined) return { name: "declarations", verdict: "fail", reason: `no topLevel slot says what a ${language} file declares` }; + const topLevel = parsedOf(language, "topLevel"); + if (topLevel === undefined) return { name: "declarations", verdict: "fail", reason: `the ${language} plugin names no treeSitter parser, so nothing says what a ${language} file declares` }; const wrong = project.declarations.filter((d) => topLevel(project.files[d.file] ?? "", d.name) !== d.declared).map((d) => `${d.name} in ${d.file} read as ${d.declared ? "not declared" : "declared"}`); return wrong.length === 0 ? { name: "declarations", verdict: "pass", reason: `${project.declarations.length} of ${project.declarations.length} read as expected` } : { name: "declarations", verdict: "fail", reason: wrong.join("; ") }; } +/** + * answers agree: where two of the language's readings answer one question of + * the same text, their answers agree over every file of the check project. A + * name the source scan finds declared is one the topLevel reading finds at + * the top level, and a type declaration where the interfaces reading reads + * one in the line alone exactly where the declares reading reads a type in + * the whole text; and every name an interfaces import list renames is one the + * source scan reads imported. Two readers of one text that disagree are how a + * reading misses what another finds (df-7ac38ee4: Python's source scan read + * nothing of a from-import split across lines, which its interfaces slot read + * whole); the parser derives each of them from one parse, so what the duty + * still finds is queries that read a declaration by what surrounds it, which + * the same queries over its line alone read otherwise. + */ +function answersAgree(project: CheckProject, language: string): Duty { + const source = parsedOf(language, "source"); + const topLevel = parsedOf(language, "topLevel"); + const declares = parsedOf(language, "declares"); + const interfaces = parsedOf(language, "interfaces"); + const files = project.language.files.filter((f) => project.files[f] !== undefined); + const wrong: string[] = []; + let compared = 0; + for (const file of files) { + const text = project.files[file]!; + const lines = text.split("\n"); + for (const d of declarationsOf(text, language)) { + const line = (lines[d.line - 1] ?? "").replace(/\r$/, ""); + if (topLevel !== undefined) { + compared++; + if (!topLevel(text, d.name)) wrong.push(`${file}:${d.line}: source declares ${d.name}, which topLevel finds no top-level declaration of`); + } + // What it declares, where two slots say: unknown is no answer (a call's result may or may not execute), so only two answers are compared. + const kind = d.declares ?? declares?.(line); + if (interfaces !== undefined && kind !== undefined && kind !== "unknown") { + compared++; + if (interfaces.isTypeDeclaration(line) !== (kind === "type")) wrong.push(`${file}:${d.line}: interfaces reads ${d.name}'s line as ${interfaces.isTypeDeclaration(line) ? "" : "no "}type declaration, declares as ${kind}`); + } + } + if (source !== undefined && interfaces !== undefined) { + const imported = new Set(); + source.importsOf(text, (name, specifier) => { + if (name !== undefined) imported.add(name); + imported.add(specifier); + imported.add(specifier.split(/[./:\\]+/).filter((s) => s !== "").pop() ?? specifier); + }); + for (const list of interfaces.importLists(text)) { + for (const [, original] of list.matchAll(/([A-Za-z_$][\w$.:]*)\s+as\s+[A-Za-z_$][\w$]*/g)) { + compared++; + if (!imported.has(original!)) wrong.push(`${file}: interfaces.importLists renames ${original}, which source.importsOf reads no import of`); + } + } + } + } + if (compared === 0) return { name: "answers agree", verdict: "fail", reason: "nothing to check: no file of the check project gives two slots one question to answer (a declaration, or a renamed import)" }; + return wrong.length === 0 ? { name: "answers agree", verdict: "pass", reason: `${compared} answers of two slots to one question agree` } : { name: "answers agree", verdict: "fail", reason: wrong.join("; ") }; +} + /** Two sorted lists' difference, said: what the reading missed and what it found that the check project names none of. */ function compared(found: readonly string[], expected: readonly string[]): string | undefined { const missed = expected.filter((e) => !found.includes(e)); @@ -401,6 +617,45 @@ async function interfacesRead(scratch: string, readings: Readings, adapter: Lang } } +/** A duty a plugin written for an older interface version is not held to, said as such and passed: it did not exist when the plugin was written. */ +function notHeld(name: "reference reading" | "server agrees", plugin: LoadedPlugin): Duty | undefined { + const { since, asks } = DUTY_SINCE[name]!; + const written = plugin.manifest.pluginApi; + return written >= since ? undefined : { name, verdict: "pass", reason: `not held: plugin ${plugin.name} is written for pluginApi ${written}, and ${name} holds from pluginApi ${since}, which brought what it asks: ${asks} (docs/plugins.md)` }; +} + +/** + * server agrees: every name the text readings find a file of the check + * project declaring at its top level is a top-level symbol the language + * server reports for that file. The server is the independent account: a + * name the reading finds and the server does not is a misread (a name read + * out of a string or a comment, as Python's line scan read 223 of PostHog's), + * whatever the check project's readings say. A name the server reports that + * the reading leaves out is no failure here, since a reading may leave names + * out by design (Python's lowercase module variables); coherence plugin + * calibrate counts those by kind over a real project. + */ +async function serverAgrees(project: CheckProject, language: string, adapter: LanguageAdapter, base: LanguageAdapter | undefined): Promise { + // An adapter that extends a language and does not ask the server itself answers through the one it wraps, which is the same server. + const ask = adapter.topLevelSymbols?.bind(adapter) ?? base?.topLevelSymbols?.bind(base); + if (ask === undefined) return { name: "server agrees", verdict: "fail", reason: "the plugin's adapter offers no topLevelSymbols, which pluginApi 3 asks of a language adapter, so the text reading's declarations cannot be held to the language server's" }; + const wrong: string[] = []; + let compared = 0; + for (const file of project.language.files) { + const text = project.files[file]; + if (text === undefined || !isSourceFile(file, language)) continue; + const declared = declarationsOf(text, language); + if (declared.length === 0) continue; + const symbols = new Set((await ask(file)).map((s) => s.name)); + for (const d of declared) { + compared++; + if (!symbols.has(d.name)) wrong.push(`${file}:${d.line}: the text reading declares ${d.name}, which the language server reports no top-level symbol of`); + } + } + if (compared === 0) return { name: "server agrees", verdict: "fail", reason: "nothing to check: the text reading finds no declaration in any file of the check project" }; + return wrong.length === 0 ? { name: "server agrees", verdict: "pass", reason: `${compared} of ${compared} declarations the text reading finds are top-level symbols the server reports` } : { name: "server agrees", verdict: "fail", reason: wrong.join("; ") }; +} + /** The plugin's adapter over the scratch project: its module's factory, handed the bundled adapter of the language it extends, which the check closes as the core does. */ function adapterOf(scratch: string, plugin: LoadedPlugin, language: string): { adapter: LanguageAdapter; base: LanguageAdapter | undefined } { if (isDefault(plugin)) return { adapter: bundledAdapter(language, scratch)!, base: undefined }; @@ -417,11 +672,11 @@ async function instrument(scratch: string, project: CheckProject, plugin: Loaded ({ adapter, base } = adapterOf(scratch, plugin, language)); } catch (error) { const reason = `the plugin's adapter could not be built: ${error instanceof Error ? error.message : String(error)}`; - return [{ name: "references", verdict: "fail", reason }, { name: "chokepoint", verdict: "fail", reason }, ...(project.readings === undefined ? [] : [{ name: "interfaces" as const, verdict: "fail" as const, reason }])]; + return [{ name: "references", verdict: "fail", reason }, notHeld("server agrees", plugin) ?? { name: "server agrees", verdict: "fail", reason }, { name: "chokepoint", verdict: "fail", reason }, ...(project.readings === undefined ? [] : [{ name: "interfaces" as const, verdict: "fail" as const, reason }])]; } try { const ready = await adapter.ready().catch((error: unknown) => ({ ok: false as const, reason: `ready() threw: ${error instanceof Error ? error.message : String(error)}` })); - if (!ready.ok) return [{ name: "references", verdict: "not run", reason: ready.reason }, { name: "chokepoint", verdict: "not run", reason: ready.reason }, ...(project.readings === undefined ? [] : [{ name: "interfaces" as const, verdict: "not run" as const, reason: ready.reason }])]; + if (!ready.ok) return [{ name: "references", verdict: "not run", reason: ready.reason }, notHeld("server agrees", plugin) ?? { name: "server agrees", verdict: "not run", reason: ready.reason }, { name: "chokepoint", verdict: "not run", reason: ready.reason }, ...(project.readings === undefined ? [] : [{ name: "interfaces" as const, verdict: "not run" as const, reason: ready.reason }])]; const hint = { component: ".", testFolders: [...DEFAULT_TEST_FOLDERS] }; const references = await guarded("references", async (): Promise => { if (project.references.length === 0) return { name: "references", verdict: "fail", reason: `nothing to check: the check project names no reference to ${project.protects}` }; @@ -435,6 +690,7 @@ async function instrument(scratch: string, project: CheckProject, plugin: Loaded if (missed.length > 0 || extra.length > 0) return { name: "references", verdict: "fail", reason: [missed.length > 0 ? `missed ${missed.join(", ")}` : "", extra.length > 0 ? `reported ${extra.join(", ")}, which is none` : ""].filter((s) => s !== "").join("; ") }; return { name: "references", verdict: "pass", reason: `${sites.length} of ${project.references.length} references to ${project.protects}` }; }); + const server = await guarded("server agrees", () => notHeld("server agrees", plugin) ?? serverAgrees(project, language, adapter, base)); // The interface reading asks the same adapter, before the chokepoint's run writes its spec. const readings = project.readings; const interfaces = readings === undefined ? [] : [await guarded("interfaces", () => interfacesRead(scratch, readings, adapter))]; @@ -453,7 +709,7 @@ async function instrument(scratch: string, project: CheckProject, plugin: Loaded ].filter((s) => s !== ""); return wrong.length === 0 ? { name: "chokepoint", verdict: "pass", reason: `${project.protects} through ${project.chokepoint} graded ${graded.grade}, refutation ${graded.refutation}` } : { name: "chokepoint", verdict: "fail", reason: wrong.join("; ") }; }); - return [references, ...interfaces, chokepoint]; + return [references, server, ...interfaces, chokepoint]; } finally { try { await adapter.close(); diff --git a/src/plugins/convex.test.ts b/src/plugins/convex.test.ts index 4434e58c..6f97ade7 100644 --- a/src/plugins/convex.test.ts +++ b/src/plugins/convex.test.ts @@ -149,8 +149,9 @@ test("a project that does not name the Convex plugin pays nothing for it: no fil test("plugin check holds a plugin that extends a language to that language's duties: the Convex plugin passes TypeScript's minimum and its own check project, a Convex chokepoint graded through it", async () => { const checked = await checkPlugin(process.cwd(), "convex"); assert.equal(checked.language, "typescript", "the language it extends"); - assert.deepEqual(checked.duties.map((d) => [d.name, d.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["references", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"]], JSON.stringify(checked.duties)); - for (const duty of checked.duties.filter((d) => d.name !== "one answer each")) assert.match(duty.reason, /the bundled minimum: .*; plugin convex's own: /, `${duty.name} is held over both projects`); + assert.deepEqual(checked.duties.map((d) => [d.name, d.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["answers agree", "pass"], ["reference reading", "pass"], ["references", "pass"], ["server agrees", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"]], JSON.stringify(checked.duties)); + // The reference project is held over the check project that maps it, TypeScript's minimum; Convex's own maps none. + for (const duty of checked.duties.filter((d) => d.name !== "one answer each" && d.name !== "reference reading")) assert.match(duty.reason, /the bundled minimum: .*; plugin convex's own: /, `${duty.name} is held over both projects`); assert.match(checked.duties.find((d) => d.name === "references")!.reason, /plugin convex's own: 9 of 9 references to send/); }); diff --git a/src/plugins/eject.test.ts b/src/plugins/eject.test.ts index f2cc820e..4f27916f 100644 --- a/src/plugins/eject.test.ts +++ b/src/plugins/eject.test.ts @@ -45,6 +45,7 @@ test("plugin eject copies a bundled plugin's source and its check.json into the assert.deepEqual(filesUnder(copy), [...filesUnder(join(PLUGIN_SOURCES, "typescript")), "package.json"].sort(), "every file of the bundled plugin, its check.json among them, and a package.json naming its modules ES modules"); assert.deepEqual(JSON.parse(readFileSync(join(copy, "package.json"), "utf8")), { type: "module", private: true }); assert.ok(filesUnder(copy).includes("check.json"), "its tests come with it"); + assert.ok(readFileSync(join(copy, "tree-sitter-tsx.wasm")).equals(readFileSync(join(PLUGIN_SOURCES, "typescript", "tree-sitter-tsx.wasm"))), "its parser copied byte for byte, never read as text"); for (const file of filesUnder(copy).filter((f) => f.endsWith(".ts"))) { const text = readFileSync(join(copy, file), "utf8"); assert.doesNotMatch(text, /"\.\.\/\.\.\/src\//, `${file} reaches into no core module`); @@ -69,7 +70,7 @@ test("plugin eject copies a bundled plugin's source and its check.json into the test("plugin check holds a plugin to every duty, bundled or by path, and a plugin that reports no references fails, by name", async (t) => { budget(t, 20, "d-467bd43d"); const bundled = await checkPlugin(process.cwd(), "typescript"); - assert.deepEqual(bundled.duties.map((o) => [o.name, o.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["references", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"]], JSON.stringify(bundled.duties)); + assert.deepEqual(bundled.duties.map((o) => [o.name, o.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["answers agree", "pass"], ["reference reading", "pass"], ["references", "pass"], ["server agrees", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"]], JSON.stringify(bundled.duties)); // A plugin that takes typescript's place and answers every references query with nothing. const root = project({ @@ -95,7 +96,7 @@ test("plugin check hands the adapter its scratch project's real path, so a serve "real/index.ts": 'import { realpathSync } from "node:fs";\nexport default { adapter: ({ root, base }) => ({ language: base.language, ladder: base.ladder, ready: async () => (realpathSync(root) === root ? base.ready() : { ok: false, reason: `handed ${root}, whose real path is ${realpathSync(root)}` }), resolve: (n, h) => base.resolve(n, h), references: (d) => base.references(d), visibility: (d, c) => base.visibility(d, c), testFilter: (v) => base.testFilter(v), refute: (p, o, e, c) => base.refute(p, o, e, c), forget: (f) => base.forget(f), close: async () => {} }) };\n', }); const checked = await checkPlugin(root, "./real"); - assert.deepEqual(checked.duties.map((o) => [o.name, o.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["references", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"]], JSON.stringify(checked.duties)); + assert.deepEqual(checked.duties.map((o) => [o.name, o.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["answers agree", "pass"], ["reference reading", "pass"], ["references", "pass"], ["server agrees", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"]], JSON.stringify(checked.duties)); }); test("plugin check passes nothing over nothing: a check.json with no cases fails each duty as nothing to check, {} is refused by name, the bundled minimum stands under a copy's own, and a duty that throws is named while the others report", async () => { @@ -124,7 +125,7 @@ test("plugin check passes nothing over nothing: a check.json with no cases fails assert.ok(shapeless.duties.every((o) => o.verdict === "fail" && /plugin honest's .*check\.json is no check project: it lacks files.*language.*declarations.*protects.*references/.test(o.reason)), JSON.stringify(shapeless.duties)); const thrown = await checkPlugin(root, "./throws"); - assert.deepEqual(thrown.duties.map((o) => o.name), ["file rule", "declarations", "references", "chokepoint", "mass", "imports", "interfaces", "entrances", "one answer each"], "every duty reported"); + assert.deepEqual(thrown.duties.map((o) => o.name), ["file rule", "declarations", "answers agree", "reference reading", "references", "server agrees", "chokepoint", "mass", "imports", "interfaces", "entrances", "one answer each"], "every duty reported"); const failed = thrown.duties.find((o) => o.name === "references")!; assert.equal(failed.verdict, "fail"); assert.match(failed.reason, /threw: deaf by design/); @@ -178,5 +179,5 @@ test("plugin check holds a plugin that both extends a language and proves via fo }); const checked = await checkPlugin(root, "./both"); assert.equal(checked.language, "typescript + verifier"); - assert.deepEqual(checked.duties.map((d) => [d.name, d.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["references", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"], ["[both exit]", "pass"]], JSON.stringify(checked.duties)); + assert.deepEqual(checked.duties.map((d) => [d.name, d.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["answers agree", "pass"], ["reference reading", "pass"], ["references", "pass"], ["server agrees", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"], ["[both exit]", "pass"]], JSON.stringify(checked.duties)); }); diff --git a/src/plugins/eject.ts b/src/plugins/eject.ts index e2c8a0eb..c80624f3 100644 --- a/src/plugins/eject.ts +++ b/src/plugins/eject.ts @@ -162,9 +162,10 @@ export function ejectPlugin(root: string, name: string, to?: string): Ejected { // A plugin the project runs bundled is the one being copied: the copy takes that entry's place. One it runs from a path is a copy already. if (name in plugins && plugins[name] !== "bundled") throw new EjectError(`plugin eject: ${CONFIG_FILE} already runs plugin ${name} from ${JSON.stringify(plugins[name])}; remove that entry to eject it again`); // Every file read and rewritten before any is written: a refusal leaves nothing behind. - const copies = filesUnder(source).map((file) => { + // A module is rewritten as text; any other file (a parser's .wasm among them) is copied byte for byte, never read as text. + const copies: { rel: string; text: string | Buffer }[] = filesUnder(source).map((file) => { const rel = relative(source, file); - return { rel, text: ejectedSource(rel, readFileSync(file, "utf8")) }; + return { rel, text: /\.[cm]?[jt]sx?$/.test(rel) ? ejectedSource(rel, readFileSync(file, "utf8")) : readFileSync(file) }; }); // The copy's modules are ES modules run as TypeScript: a package.json saying so, unless it carries one, keeps Node from guessing (and // warning) at every load, whatever the project's own package.json says. diff --git a/src/plugins/fixtures/ejected-1.10.1/typescript/check.json b/src/plugins/fixtures/ejected-1.10.1/typescript/check.json new file mode 100644 index 00000000..786eb71b --- /dev/null +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/check.json @@ -0,0 +1,108 @@ +{ + "files": { + "tsconfig.json": "{ \"compilerOptions\": { \"target\": \"ES2022\", \"module\": \"NodeNext\", \"moduleResolution\": \"NodeNext\", \"strict\": true, \"noEmit\": true, \"allowImportingTsExtensions\": true }, \"include\": [\"src/**/*.ts\"] }\n", + "src/store/secrets.ts": "/** The protected thing. */\nexport const SECRET_COLUMNS: Record = { tokens: [\"token\"] };\n\n/** The chokepoint: the one way a row leaves without its secrets. */\nexport function seal(pattern: string, row: Record): Record {\n const out = { ...row };\n for (const column of SECRET_COLUMNS[pattern] ?? []) delete out[column];\n return out;\n}\n", + "src/api/render.ts": "import { SECRET_COLUMNS, seal } from \"../store/secrets.ts\";\n\nexport function render(pattern: string, row: Record): string {\n const sealed = seal(pattern, row);\n const leaked = SECRET_COLUMNS[pattern];\n return JSON.stringify({ sealed, leaked });\n}\n", + "src/__tests__/secrets.test.ts": "import { SECRET_COLUMNS } from \"../store/secrets.ts\";\nexport const t = SECRET_COLUMNS;\n", + "README.md": "# A project\n", + "src/api/routes.ts": "import { render } from \"./render.ts\";\n\nexport const app = {\n get(path: string, handler: (row: Record) => string): readonly [string, (row: Record) => string] {\n return [path, handler] as const;\n },\n};\n\nexport function rows(row: Record): string {\n return render(\"tokens\", row);\n}\n\napp.get(\"/rows\", rows);\n" + }, + "language": { + "files": [ + "src/store/secrets.ts", + "src/api/render.ts", + "src/app.tsx", + "src/legacy.mjs" + ], + "not": [ + "README.md", + "src/types.d.ts", + "tsconfig.json" + ] + }, + "declarations": [ + { + "file": "src/store/secrets.ts", + "name": "SECRET_COLUMNS", + "declared": true + }, + { + "file": "src/store/secrets.ts", + "name": "seal", + "declared": true + }, + { + "file": "src/store/secrets.ts", + "name": "out", + "declared": false + }, + { + "file": "src/api/render.ts", + "name": "SECRET_COLUMNS", + "declared": false + } + ], + "protects": "SECRET_COLUMNS", + "chokepoint": "seal", + "references": [ + "src/__tests__/secrets.test.ts:1", + "src/__tests__/secrets.test.ts:2", + "src/api/render.ts:1", + "src/api/render.ts:5", + "src/store/secrets.ts:7" + ], + "grade": "broken", + "bypasses": [ + "src/api/render.ts:1", + "src/api/render.ts:5" + ], + "readings": { + "declared": { + "src/api/render.ts": [ + "render" + ], + "src/api/routes.ts": [ + "app", + "rows" + ], + "src/store/secrets.ts": [ + "SECRET_COLUMNS", + "seal" + ] + }, + "imports": [ + { + "file": "src/api/render.ts", + "module": "src/store/secrets.ts", + "names": [ + "SECRET_COLUMNS", + "seal" + ] + }, + { + "file": "src/api/routes.ts", + "module": "src/api/render.ts", + "names": [ + "render" + ] + } + ], + "interfaces": [ + { + "from": "src/api", + "to": "src/store", + "symbols": [ + "SECRET_COLUMNS", + "seal" + ] + } + ], + "entrances": [ + { + "file": "src/api/routes.ts", + "symbol": "rows", + "rule": "route method" + } + ] + } +} diff --git a/src/plugins/fixtures/ejected-1.10.1/typescript/index.ts b/src/plugins/fixtures/ejected-1.10.1/typescript/index.ts new file mode 100644 index 00000000..cb6a231c --- /dev/null +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/index.ts @@ -0,0 +1,14 @@ +/** + * The TypeScript plugin: Coherence's own reading of TypeScript and + * JavaScript, bundled with the package and run by every project unless its + * config names a plugin that provides typescript in this one's place. + */ + +import type { PluginModule } from "@posthog/coherence/plugin"; +import { TypeScriptAdapter } from "./typescript.ts"; + +const typescript: PluginModule = { + adapter: ({ root }) => new TypeScriptAdapter(root), +}; + +export default typescript; diff --git a/src/plugins/fixtures/ejected-1.10.1/typescript/package.json b/src/plugins/fixtures/ejected-1.10.1/typescript/package.json new file mode 100644 index 00000000..8898b262 --- /dev/null +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/package.json @@ -0,0 +1 @@ +{ "type": "module", "private": true } diff --git a/src/plugins/fixtures/ejected-1.10.1/typescript/plugin.json b/src/plugins/fixtures/ejected-1.10.1/typescript/plugin.json new file mode 100644 index 00000000..63070904 --- /dev/null +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/plugin.json @@ -0,0 +1,132 @@ +{ + "name": "typescript", + "version": "1.10.1", + "pluginApi": 2, + "provides": { + "language": "typescript" + }, + "files": { + "pattern": "\\.(?:[cm]?[tj]sx?)$", + "except": "\\.d\\.ts$" + }, + "source": { + "except": "\\.[cm]?jsx?$" + }, + "serverExtensions": [ + ".ts", + ".tsx", + ".mts", + ".cts", + ".js", + ".jsx", + ".mjs", + ".cjs" + ], + "basisFiles": [ + "^tsconfig(?:\\.[\\w-]+)*\\.json$", + "^jsconfig\\.json$", + "^package\\.json$", + "^pnpm-lock\\.yaml$", + "^package-lock\\.json$", + "^yarn\\.lock$", + "^bun\\.lockb?$" + ], + "members": { + "opens": "^export\\s+(?:default\\s+)?(?:declare\\s+)?(?:abstract\\s+)?(?:interface|type|class)\\s.*\\{\\s*$", + "closes": "^[}\\]]", + "field": "^\\s+(?:readonly\\s+)?([a-z][A-Za-z0-9]*)\\??:\\s*[^=]" + }, + "entrances": { + "rules": [ + { + "rule": "server function", + "plural": "server functions", + "detects": "an exported const created by createServerFn (TanStack Start)" + }, + { + "rule": "wrapped export", + "plural": "wrapped exports", + "detects": "an exported const created by calling a symbol a declared entrance names as its handler or guard" + }, + { + "rule": "server route", + "plural": "server routes", + "detects": "an exported route created by createFileRoute with server handlers, createServerFileRoute or createAPIFileRoute" + }, + { + "rule": "route handler", + "plural": "route handlers", + "detects": "a GET, POST, PUT, PATCH, DELETE, HEAD or OPTIONS a Next.js app/**/route file exports, declared there, in an export list or re-export, or destructured; a default export under pages/api; or an exported loader or action under app/routes" + }, + { + "rule": "request proxy", + "plural": "request proxies", + "detects": "the proxy a Next.js proxy.ts exports, or the middleware a middleware.ts exports, at the root or under src/: declared, in an export list or re-export, or as the default export" + }, + { + "rule": "page route", + "plural": "page routes", + "detects": "the default export of a Next.js app/**/page file, the page as a whole" + }, + { + "rule": "server action", + "plural": "server actions", + "detects": "an exported function of a file that opens with 'use server'" + }, + { + "rule": "route table", + "plural": "route table entries", + "detects": "an object literal naming a path or pattern that starts with / and a handler, on one line" + }, + { + "rule": "route method", + "plural": "registered routes", + "detects": "a call like app.get('/path', handler) whose first argument is a path starting with /" + }, + { + "rule": "package bin", + "plural": "package bins", + "detects": "a file package.json's bin names" + }, + { + "rule": "package script", + "plural": "package scripts", + "detects": "a project file a package.json script runs with node, tsx, ts-node, bun, deno, vite-node or python" + }, + { + "rule": "script", + "plural": "scripts", + "detects": "a file directly under a top-level scripts/ or bin/ folder that no project file imports" + } + ], + "notDetected": "file routes outside a Next.js app/**/page without server handlers (their work enters through server functions), hand-written dispatchers, message consumers, workers and host callbacks are not detected" + }, + "environmentFolders": [ + "node_modules" + ], + "ladder": { + "top": "visibility-choked", + "because": "a symbol not exported from its module cannot be referenced from another module; the compiler refuses it", + "rungs": [ + { + "grade": "visibility-choked", + "enforcer": "the compiler", + "fact": "the protected thing is not exported from its module, so no other module can reference it" + }, + { + "grade": "reference-choked", + "enforcer": "Coherence's check at the edit and in CI", + "fact": "the protected thing is exported, and every resolved reference in the project is inside the chokepoint" + } + ] + }, + "module": "index.ts", + "syntax": { + "entrances": "typescript-entrances.ts#TYPESCRIPT_ENTRANCES", + "interfaces": "typescript-scope.ts#TYPESCRIPT_INTERFACES", + "source": "typescript-source.ts#TYPESCRIPT_SOURCE", + "declares": "typescript-interfaces.ts#typescriptDeclares", + "notice": "tsserver.ts#tsserverNotice", + "topLevel": "typescript-top-level.ts#typescriptDeclaresAtTop" + } +} diff --git a/src/plugins/fixtures/ejected-1.10.1/typescript/tsserver.ts b/src/plugins/fixtures/ejected-1.10.1/typescript/tsserver.ts new file mode 100644 index 00000000..57647245 --- /dev/null +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/tsserver.ts @@ -0,0 +1,51 @@ +/** + * Which tsserver the TypeScript language server drives, and the one line a + * session start says when it is not the project's own: the project's + * typescript/lib/tsserver.js while it ships one (TypeScript below 7), else + * Coherence's own. Packages are found through installed.ts, by the resolver. + */ + +import { COHERENCE_FROM, installedPackage, packageFile, projectFrom } from "@posthog/coherence/plugin"; + +/** The first number of a version. */ +function major(version: string): number { + return Number.parseInt(version, 10); +} + +/** The tsserver the TypeScript language server drives, whose it is, and, when it is Coherence's, the project's TypeScript it stands in for. */ +export interface TsserverChoice { + path: string; + version: string; + whose: "project" | "coherence"; + /** The project's own TypeScript when it is installed but ships no tsserver (TypeScript 7 and later). */ + passedOver: string | undefined; +} + +/** + * The tsserver to drive: the project's own typescript/lib/tsserver.js when + * that file exists and is a tsserver (TypeScript below 7: from 7 the language + * service is native and ships none), otherwise Coherence's own, resolved from + * its module; undefined when neither holds one. + */ +export function locateTsserver(root: string, coherenceFrom: string = COHERENCE_FROM): TsserverChoice | undefined { + const project = installedPackage("typescript", projectFrom(root)); + const own = project === undefined ? undefined : packageFile(project, "lib/tsserver.js"); + if (project !== undefined && own !== undefined && major(project.version) < 7) return { path: own, version: project.version, whose: "project", passedOver: undefined }; + const passedOver = project === undefined ? undefined : project.version; + const coherence = installedPackage("typescript", coherenceFrom); + const theirs = coherence === undefined ? undefined : packageFile(coherence, "lib/tsserver.js"); + if (coherence !== undefined && theirs !== undefined && major(coherence.version) < 7) return { path: theirs, version: coherence.version, whose: "coherence", passedOver }; + return undefined; +} + +/** + * The line an agent reads when the project's TypeScript ships no tsserver and + * Coherence reads with its own; empty otherwise. + */ +export function tsserverNotice(root: string, coherenceFrom: string = COHERENCE_FROM): string { + const project = installedPackage("typescript", projectFrom(root)); + if (project === undefined || major(project.version) < 7) return ""; + const choice = locateTsserver(root, coherenceFrom); + if (choice === undefined) return `TypeScript: this project's TypeScript ${project.version} ships no tsserver and Coherence has no TypeScript of its own installed, so no TypeScript reading can be made; install Coherence with its optional dependencies (its typescript is one).`; + return `TypeScript: this project's TypeScript ${project.version} ships no tsserver, so Coherence is using its own TypeScript ${choice.version} for readings (references, symbols and the compiler's refusals).`; +} diff --git a/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-entrances.ts b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-entrances.ts new file mode 100644 index 00000000..9dcd6507 --- /dev/null +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-entrances.ts @@ -0,0 +1,171 @@ +/** + * TypeScript's entrance rules and the syntax they read by: the shapes + * Next.js, Remix, TanStack Start and the HTTP routers fix, how a statement + * spans its lines, what binds a name, which scripts run rather than are + * imported (entrance-candidates.ts reads them through ENTRANCE_SYNTAX). + */ + +import { posix } from "node:path"; +import { languageOfFile } from "@posthog/coherence/plugin"; +import { escape, handlerName, lineOf, NEXT_ROUTE_METHODS, REMIX_ROUTE_EXPORTS, spanOf, throughOf, type EntranceCandidate, type EntranceSyntax } from "@posthog/coherence/plugin"; + +/** The text from its first code: leading whitespace and comments skipped by a walk, never a backtracking pattern. */ +function leadingCode(text: string): string { + let i = 0; + for (;;) { + while (i < text.length && /\s/.test(text[i]!)) i += 1; + if (text.startsWith("//", i)) { + const end = text.indexOf("\n", i); + i = end < 0 ? text.length : end + 1; + } else if (text.startsWith("/*", i)) { + const end = text.indexOf("*/", i + 2); + i = end < 0 ? text.length : end + 2; + } else return text.slice(i); + } +} + +function typescriptCandidates(file: string, text: string, wrappers: readonly string[]): EntranceCandidate[] { + const out: EntranceCandidate[] = []; + const lines = text.split("\n"); + // The file's own top-level helpers, so a route whose handlers are a local `handle` calling the wrapper is registered through it. + const helpers = new Map(); + lines.forEach((line, i) => { + const m = /^(?:export\s+)?(?:async\s+)?(?:function\*?\s*|const\s+|let\s+|var\s+)([A-Za-z_$][\w$]*)/.exec(line); + if (m !== null && !helpers.has(m[1]!)) helpers.set(m[1]!, i); + }); + const add = (c: Omit, span: string): void => { + let through = throughOf(span, text, wrappers, TYPESCRIPT_ENTRANCES); + if (through === undefined) { + // One level into the file's own helpers the statement names, never further. + const named = [...helpers].filter(([name, at]) => at !== c.line - 1 && new RegExp(`(? 0) through = throughOf(named.map(([, at]) => spanOf(lines, at, TYPESCRIPT_ENTRANCES)).join("\n"), text, wrappers, TYPESCRIPT_ENTRANCES); + } + out.push(through === undefined ? c : { ...c, through }); + }; + const wrapperSet = new Set(wrappers); + const nextRoute = /(^|\/)app\/(.+\/)?route\.(ts|tsx|js|mjs)$/.test(file); + const pagesApi = /(^|\/)pages\/api\/.+\.(ts|tsx|js|mjs)$/.test(file); + const remixRoute = /(^|\/)app\/routes\/.+\.(ts|tsx|js|jsx)$/.test(file); + const useServer = /^["']use server["']/.test(leadingCode(text)); + // Next.js's request proxy (proxy.ts since Next.js 16, middleware.ts before it), at the project root or under src/. + const proxyFile = /^(?:src\/)?(proxy|middleware)\.(ts|js|mjs)$/.exec(file)?.[1]; + const nextPage = /(^|\/)app\/(.+\/)?page\.(tsx|jsx|ts|js)$/.test(file) && !remixRoute; + if (nextRoute || proxyFile !== undefined) { + // What a route or proxy file exports by name without declaring it: an export list, re-exported or local, or a destructuring + // (export { GET, POST } from "@/app/(auth)/auth", export { auth as proxy }, export const { GET, POST } = handlers). + const wanted = (name: string): boolean => (nextRoute ? NEXT_ROUTE_METHODS.has(name) : name === proxyFile); + for (const m of text.matchAll(/^export\s*\{([^}]*)\}|^export\s+(?:const|let|var)\s*\{([^}]*)\}\s*=/gm)) { + const listed = m[1] !== undefined; + const reexported = listed && /^\s*from\s*["']/.test(text.slice(m.index + m[0].length)); + for (const item of (m[1] ?? m[2]!).split(",")) { + const named = listed ? /^\s*([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?\s*$/.exec(item) : /^\s*(?:[A-Za-z_$][\w$]*\s*:\s*)?([A-Za-z_$][\w$]*)\s*$/.exec(item); + const name = named === null ? undefined : (named[2] ?? named[1]!); + if (name === undefined || !wanted(name)) continue; + const line = lineOf(text, m.index); + const how = reexported ? "re-exported" : "exported by name"; + const c = nextRoute + ? { file, line, symbol: name, rule: "route handler", why: `${name} ${how} in a Next.js route file: answers ${name} requests` } + : { file, line, symbol: name, rule: "request proxy", why: `${name} ${how} in ${file}: Next.js runs it before every request it matches` }; + add(c, spanOf(lines, line - 1, TYPESCRIPT_ENTRANCES)); + } + } + if (proxyFile !== undefined) { + const at = lines.findIndex((l) => /^export\s+default\b/.test(l)); + if (at >= 0) add({ file, line: at + 1, symbol: "", rule: "request proxy", why: `the default export of ${file}: Next.js runs it before every request it matches` }, spanOf(lines, at, TYPESCRIPT_ENTRANCES)); + } + } + const at = nextPage ? lines.findIndex((l) => /^export\s+default\b/.test(l)) : -1; + if (at >= 0) { + add({ file, line: at + 1, symbol: "", rule: "page route", why: "the default export of a Next.js app/**/page file: renders its route on the server for every visitor" }, spanOf(lines, at, TYPESCRIPT_ENTRANCES)); + } + lines.forEach((line, i) => { + const declared = proxyFile === undefined ? null : /^export\s+(?:async\s+)?(?:function\s*\*?\s*|const\s+|let\s+|var\s+)([A-Za-z_$][\w$]*)/.exec(line); + if (declared !== null && declared[1] === proxyFile) { + add({ file, line: i + 1, symbol: proxyFile!, rule: "request proxy", why: `export ${proxyFile} in ${file}: Next.js runs it before every request it matches` }, spanOf(lines, i, TYPESCRIPT_ENTRANCES)); + return; + } + const exported = /^export\s+const\s+([A-Za-z_$][\w$]*)\s*(?::[^=]+)?=\s*(?:await\s+)?([A-Za-z_$][\w$]*)\s*(?:<[^()]*>)?\s*\(/.exec(line); + if (exported !== null) { + const [, name, callee] = exported as unknown as [string, string, string]; + const span = spanOf(lines, i, TYPESCRIPT_ENTRANCES); + if (callee === "createServerFn") { + add({ file, line: i + 1, symbol: name, rule: "server function", why: `export const ${name} = createServerFn(...): a TanStack Start server function a browser can call` }, span); + return; + } + if (callee === "createServerFileRoute" || callee === "createAPIFileRoute" || (callee === "createFileRoute" && /\bserver\s*:\s*\{[\s\S]*\bhandlers\b/.test(span))) { + add({ file, line: i + 1, symbol: name, rule: "server route", why: `export const ${name} = ${callee}(...)${callee === "createFileRoute" ? " with server handlers" : ""}: a route that answers requests on the server` }, span); + return; + } + if (wrapperSet.has(callee)) { + add({ file, line: i + 1, symbol: name, rule: "wrapped export", why: `export const ${name} = ${callee}(...): created by ${callee}, which a declared entrance names` }, span); + return; + } + } + const fn = /^export\s+(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)|^export\s+const\s+([A-Za-z_$][\w$]*)\s*(?::[^=]+)?=\s*(?:async\b|\(|function\b)/.exec(line); + const fnName = fn?.[1] ?? fn?.[2]; + if (fnName !== undefined) { + const span = spanOf(lines, i, TYPESCRIPT_ENTRANCES); + if (nextRoute && NEXT_ROUTE_METHODS.has(fnName)) add({ file, line: i + 1, symbol: fnName, rule: "route handler", why: `export ${fnName} in a Next.js route file: answers ${fnName} requests` }, span); + else if (remixRoute && REMIX_ROUTE_EXPORTS.has(fnName)) add({ file, line: i + 1, symbol: fnName, rule: "route handler", why: `export ${fnName} in app/routes: runs on the server for its route` }, span); + else if (useServer && /^export\s+(?:async\s+function|const\s+\w+\s*(?::[^=]+)?=\s*async\b)/.test(line)) add({ file, line: i + 1, symbol: fnName, rule: "server action", why: `export ${fnName} in a 'use server' file: a server action a browser can call` }, span); + } + if (pagesApi && /^export\s+default\b/.test(line)) add({ file, line: i + 1, symbol: "", rule: "route handler", why: "the default export under pages/api: a Next.js API route" }, spanOf(lines, i, TYPESCRIPT_ENTRANCES)); + const table = /\b(?:pattern|path|route)\s*:\s*["'`](\/[^"'`]*)["'`][^\n]*?\bhandler\s*:\s*([A-Za-z_$][\w$.]*(?:\s*\(\s*[A-Za-z_$][\w$.]*\s*\))?)/.exec(line); + if (table !== null) { + const symbol = handlerName(table[2]!); + if (symbol !== "") add({ file, line: i + 1, symbol, rule: "route table", why: `a route table entry: ${table[1]} handled by ${table[2]!.trim()}`, registered: true }, line); + return; + } + // A statement, never text inside a string: the call opens its line, as `app.get(...)`, `await router.post(...)` or a chained `.get(...)`. + const method = /^\s*(?:await\s+)?(?:[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)?\.(get|post|put|patch|delete|all|head|options)\(\s*["'`](\/[^"'`]*)["'`]\s*,([^\n]*)$/.exec(line); + if (method !== null) { + const last = /,?\s*([A-Za-z_$][\w$.]*)\s*\)\s*;?\s*$/.exec(method[3]!); + const symbol = last === null ? "" : handlerName(last[1]!); + add({ file, line: i + 1, symbol, rule: "route method", why: `${method[1]!.toUpperCase()} ${method[2]} registered by a .${method[1]}() call${symbol === "" ? " with an inline handler" : ` to ${symbol}`}`, ...(symbol === "" ? {} : { registered: true as const }) }, spanOf(lines, i, TYPESCRIPT_ENTRANCES)); + } + }); + return out; +} + +const TS_IMPORT = /(?:\bfrom\s*|\bimport\s*\(\s*|\brequire\s*\(\s*|^\s*import\s+)["'](\.{1,2}\/[^"']+)["']/gm; + +/** The code files some other code file imports by a relative path. */ +function importedFiles(files: readonly string[], read: (file: string) => string | undefined): Set { + const all = new Set(files); + const out = new Set(); + for (const file of files) { + const text = read(file); + if (text === undefined) continue; + for (const m of text.matchAll(TS_IMPORT)) { + const joined = posix.normalize(posix.join(posix.dirname(file), m[1]!)); + const stem = joined.replace(/\.(js|mjs|cjs|jsx)$/, ""); + for (const c of [joined, ...[".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs"].map((e) => stem + e), ...[".ts", ".tsx", ".js"].map((e) => posix.join(joined, "index" + e))]) { + if (all.has(c) && c !== file) out.add(c); + } + } + } + return out; +} + +/** Whether the file imports or declares the name: an import clause naming it, or a function, class or binding of it. */ +function binds(text: string, name: string): boolean { + const n = escape(name); + for (const m of text.matchAll(/\bimport\s[^"'`;]*?\bfrom\s*["'][^"']+["']/g)) if (new RegExp(`(? languageOfFile(file) === "typescript", + definitionAt: (_lines, start) => start, + continues: (text) => /^\s*[)\]}.]/.test(text), + binds, + decorates: false, + candidates: typescriptCandidates, + manifestCandidates: () => [], + script(file, folder, _read, imported) { + if (imported.has(file)) return undefined; + return { file, line: 1, symbol: "", rule: "script", why: `a script directly under ${folder}/ that no project file imports` }; + }, + importedAmong: importedFiles, +}; diff --git a/plugins/typescript/typescript-interfaces.ts b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-interfaces.ts similarity index 94% rename from plugins/typescript/typescript-interfaces.ts rename to src/plugins/fixtures/ejected-1.10.1/typescript/typescript-interfaces.ts index 9b048b66..9c590f32 100644 --- a/plugins/typescript/typescript-interfaces.ts +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-interfaces.ts @@ -3,7 +3,7 @@ * keyword says can execute (interfaces.ts reads them through DECLARES). */ -import type { InterfaceSymbol } from "../../src/plugins/api.ts"; +import type { InterfaceSymbol } from "@posthog/coherence/plugin"; /** An interface or type alias is a type, an enum or namespace a value; a binding is read by what it is bound to. */ export function typescriptDeclares(line: string): InterfaceSymbol["declares"] { diff --git a/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-scope.ts b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-scope.ts new file mode 100644 index 00000000..bab7051a --- /dev/null +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-scope.ts @@ -0,0 +1,29 @@ +/** + * TypeScript's facts for the component interface reading: which declaration + * lines are types or default exports, and what the word index and the kept + * answers read of a file's imports (component-interfaces.ts reads them + * through INTERFACE_SYNTAX, and kept-answers.ts through its wildcardModules). + */ + +import { specifierCandidates } from "./typescript.ts"; +import type { InterfaceSyntax } from "@posthog/coherence/plugin"; + +/** A TypeScript import or export list: `import { a as b } from`, `export { a as b }`, `export type { … }`. */ +const TS_LIST = /\b(?:import|export)\s+(?:type\s+)?(?:[A-Za-z_$][\w$]*\s*,\s*)?\{([^}]*)\}/g; +/** A TypeScript default export by name: `export default foo;`, `export = foo`, `export { foo as default }` is read as an alias to "default". */ +const TS_DEFAULT_NAME = /^export\s+(?:default\s+|=\s*)([A-Za-z_$][\w$]*)\s*;?\s*$/gm; +const TS_WILDCARD = /^export\s+(?:type\s+)?\*(?:\s+as\s+[A-Za-z_$][A-Za-z0-9_$]*)?\s+from\s*["']([^"']+)["']/gm; + +/** Interfaces and type aliases are types; `export default` is the default export; the server reads its tsconfig's project, so it takes no bounds. */ +export const TYPESCRIPT_INTERFACES: InterfaceSyntax = { + isTypeDeclaration: (line) => /^(?:export\s+)?(?:declare\s+)?(?:interface|type)\s/.test(line.trim()), + isDefaultExport: (line) => /^export\s+default\s/.test(line.trim()), + serverBounds: false, + importLists: (text) => [...text.matchAll(TS_LIST)].map((m) => m[1]!), + defaultNames: (text) => [...text.matchAll(TS_DEFAULT_NAME)].map((m) => m[1]!), + // Every file the specifier may name: without the file list, `./foo.js` is foo.ts in a NodeNext project and foo.js in a JavaScript one. + wildcardModules(file, text) { + return [...text.matchAll(TS_WILDCARD)].flatMap(([, specifier]) => specifierCandidates(file, specifier!)); + }, +}; + diff --git a/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-source.ts b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-source.ts new file mode 100644 index 00000000..3ac7891e --- /dev/null +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-source.ts @@ -0,0 +1,52 @@ +/** + * TypeScript's facts for the plain source scan: which top-level names a + * line declares, which names a file imports, and where a relative specifier + * resolves (source.ts reads them through SOURCE_SYNTAX). + */ + +import { statSync } from "node:fs"; +import { posix, resolve } from "node:path"; +import { isSourceFile, toRelative, type SourceSyntax } from "@posthog/coherence/plugin"; + +const TS_DECLARATION = /^(export\s+)?(?:default\s+)?(?:declare\s+)?(?:abstract\s+)?(?:async\s+)?(?:function\*?|const|let|var|class|interface|type|enum|namespace)\s+([A-Za-z_$][\w$]*)/; +const TS_NAMED = /import\s+(?:type\s+)?\{([^}]*)\}\s*from\s*["']([^"']+)["']/g; +const TS_DEFAULT = /import\s+(?:type\s+)?([A-Za-z_$][\w$]*)\s*(?:,\s*\{[^}]*\})?\s*from\s*["']([^"']+)["']/g; +const TS_NAMESPACE = /import\s+(?:type\s+)?\*\s+as\s+[A-Za-z_$][\w$]*\s+from\s*["']([^"']+)["']/g; +const TS_SIDE = /(?:^|\n)\s*import\s*["']([^"']+)["']/g; + +/** A declaration is exported when its line says `export`; only a relative specifier names a project file. */ +export const TYPESCRIPT_SOURCE: SourceSyntax = { + declarationOf(line) { + const m = TS_DECLARATION.exec(line); + return m === null ? undefined : { name: m[2]!, exported: m[1] !== undefined }; + }, + resolveModule(root, from, specifier, vanished) { + if (!specifier.startsWith(".")) return undefined; + const joined = posix.normalize(posix.join(posix.dirname(from), specifier)); + const candidates = [joined, ...[".ts", ".tsx", ".mts", ".cts"].map((ext) => joined.replace(/\.js$/, "") + ext), ...[".ts", ".tsx"].map((ext) => posix.join(joined, "index" + ext))]; + for (const candidate of candidates) { + const rel = toRelative(root, resolve(root, candidate)); + if (rel === undefined) continue; + if (vanished.has(rel) && isSourceFile(rel, "typescript")) return rel; + try { + if (statSync(resolve(root, rel)).isFile() && isSourceFile(rel, "typescript")) return rel; + } catch { + // Not there; try the next. + } + } + return undefined; + }, + importsOf(text, add) { + for (const m of text.matchAll(TS_NAMED)) { + for (const piece of m[1]!.split(",")) { + const cleaned = piece.replace(/^\s*type\s+/, "").trim(); + if (cleaned === "") continue; + const original = cleaned.split(/\s+as\s+/)[0]!.trim(); + add(original, m[2]!); + } + } + for (const m of text.matchAll(TS_DEFAULT)) add("default", m[2]!); + for (const m of text.matchAll(TS_NAMESPACE)) add(undefined, m[1]!); + for (const m of text.matchAll(TS_SIDE)) add(undefined, m[1]!); + }, +}; diff --git a/plugins/typescript/typescript-top-level.ts b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript-top-level.ts similarity index 100% rename from plugins/typescript/typescript-top-level.ts rename to src/plugins/fixtures/ejected-1.10.1/typescript/typescript-top-level.ts diff --git a/src/plugins/fixtures/ejected-1.10.1/typescript/typescript.ts b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript.ts new file mode 100644 index 00000000..8974506e --- /dev/null +++ b/src/plugins/fixtures/ejected-1.10.1/typescript/typescript.ts @@ -0,0 +1,928 @@ +/** + * The TypeScript adapter: the language server protocol over stdio to + * typescript-language-server, resolved from the adopter's project first, + * then from Coherence's own module (it is an optional dependency), then on + * PATH; never by a path built by hand (installed.ts). + * + * Symbols resolve through workspace/symbol (a bare name) or the hinted + * file's textDocument/documentSymbol (`name in file.ts`); a module is its + * file. References come from textDocument/references, and every site the + * server reports is a reference, an import or re-export specifier + * included: the adapter reports the syntactic form it read at the site and + * exempts nothing, and what the form means is the check's question, not the + * adapter's. A wildcard re-export (`export * from`) names no symbol, so the + * server reports no site for it and the adapter scans its own source files + * for one, once per forget. Exportedness is not in the protocol, so the + * adapter reads the declaration text. The refutation stages a re-export + * beside the protected thing and a use in the chokepoint's own module past + * its range; for a thing the module does not export, it opens the synthetic + * import instead and reads the compiler's refusal back from the published + * diagnostics. + * + * TypeScript enforces visibility: a symbol not exported from its module is + * unreachable from any other module, so the top rung is visibility-choked. + */ + +import { existsSync, readFileSync, statSync } from "node:fs"; +import { dirname, join, relative, resolve, sep } from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import { createHash, randomBytes } from "node:crypto"; +import { + isTestPath, + outsideOfFolder, + parseName, + rangeContains, + statementStartLine, + withinFolder, + type Definition, + type Ladder, + type LanguageAdapter, + type Position, + type Range, + type ReferenceSite, + type Refutation, + type ResolveHint, + type Resolved, + type SiteForm, + type StagedSite, + type Visibility, +} from "@posthog/coherence/plugin"; +import { locateServer as locateInstalled, type ServerLocation } from "@posthog/coherence/plugin"; +import { locateTsserver } from "./tsserver.ts"; +import manifest from "./plugin.json" with { type: "json" }; +import { JsonRpcClient } from "@posthog/coherence/plugin"; +import { fileIdentity, hintedFiles, horizonFolders, keepHorizonFiles, keepProjectFiles, projectListing, walkBounds, walkedProjectFiles, type ProjectListing } from "@posthog/coherence/plugin"; + +const SERVER_BIN = "typescript-language-server"; +const TYPESCRIPT_EXTENSIONS = new Set([".ts", ".tsx", ".mts", ".cts"]); +const JAVASCRIPT_EXTENSIONS = new Set([".js", ".jsx", ".mjs", ".cjs"]); +const SOURCE_EXTENSIONS = new Set([...TYPESCRIPT_EXTENSIONS, ...JAVASCRIPT_EXTENSIONS]); + +/** + * The sources the project is written in: when any TypeScript source is in the + * walk, only the TypeScript sources, since a JavaScript file beside them is + * compiled output a repository tracks (`dist/`, `lib/`) or a loose script, + * and a seed or a text search that reaches for it lands in an inferred + * project around the compiled copy; a project with no TypeScript source is + * written in JavaScript, and those files are its sources. A mixed project + * that compiles with `allowJs` still has a TypeScript seed, and the project + * that seed loads includes its JavaScript modules, so their symbols resolve + * through the server rather than through this list. + */ +export function projectSources(files: readonly string[]): string[] { + const sources = files.filter((rel) => SOURCE_EXTENSIONS.has(extensionOf(rel)) && !/\.d\.ts$/.test(rel)); + const typescript = sources.filter((rel) => TYPESCRIPT_EXTENSIONS.has(extensionOf(rel))); + return typescript.length > 0 ? typescript : sources; +} + +/** The LSP language id tsserver expects for a file: a JavaScript file opened as "typescript" is parsed as TypeScript, is not the file the project knows, and every later query about it fails. */ +function languageIdOf(file: string): "typescript" | "typescriptreact" | "javascript" | "javascriptreact" { + const extension = extensionOf(file); + if (extension === ".tsx") return "typescriptreact"; + if (extension === ".jsx") return "javascriptreact"; + return JAVASCRIPT_EXTENSIONS.has(extension) ? "javascript" : "typescript"; +} + +/** The extension a synthetic document beside `file` takes, so the project that includes `file` includes the synthetic too: a `.ts` probe beside a `.mjs` module lands in an inferred project the references query never sees. */ +function syntheticExtensionBeside(file: string): string { + const extension = extensionOf(file); + return JAVASCRIPT_EXTENSIONS.has(extension) ? extension : ".ts"; +} + +/** The ladder, as this plugin's manifest declares it for the core to read without loading this module. */ +export const TYPESCRIPT_LADDER: Ladder = manifest.ladder as Ladder; + +/** Where the language server binary is, with every place looked. */ +export function locateServer(root: string): ServerLocation { + return locateInstalled(SERVER_BIN, SERVER_BIN, root); +} + +interface DocumentSymbol { + name: string; + kind: number; + range: Range; + selectionRange: Range; + children?: DocumentSymbol[]; +} + +interface SymbolInformation { + name: string; + kind: number; + location: { uri: string; range: Range }; + containerName?: string; +} + +interface Location { + uri: string; + range: Range; +} + +interface Diagnostic { + message: string; + severity?: number; + code?: number | string; + source?: string; +} + +/** + * Whether a diagnostic is the compiler refusing a reference because the name + * is not exported or not accessible — the refusal that stands as the + * refutation for the rung the compiler enforces (ruling rs-e93ecdd6). TS2459 + * is "declares it locally, but it is not exported"; TS2305 "has no exported + * member"; TS2341 and TS2445 are private and protected access. + */ +export function refusesReference(diagnostic: Diagnostic): boolean { + if (diagnostic.severity !== undefined && diagnostic.severity !== 1) return false; + if ([2459, 2305, 2341, 2445, 2694, 2724].includes(Number(diagnostic.code))) return true; + return /not exported|no exported member|is private|is protected|not accessible/.test(diagnostic.message); +} + +/** The project's files a walk of this adapter may read: the walk's own bounds (walkedProjectFiles), never the config's ignore list. */ +function walkedFiles(root: string): string[] { + return walkedProjectFiles(walkBounds(root, [])).files; +} + +/** + * The source file opening which makes the language server load the project: + * the first one inside a component folder (a folder holding a spec) when + * there is one, since a source file the tsconfig does not include (a bench + * script, a promo build) loads only an inferred project around itself and + * leaves the project's own symbols unsearchable; otherwise the first source + * file of the walk. + */ +export function seedFile(files: readonly string[]): string | undefined { + const sources = projectSources(files); + const components = [...new Set(files.filter((rel) => rel.endsWith(".spec.md")).map((rel) => (rel.includes("/") ? rel.slice(0, rel.lastIndexOf("/")) : ".")))].filter((f) => f !== "."); + return sources.find((rel) => components.some((folder) => rel.startsWith(`${folder}/`))) ?? sources[0]; +} + +function firstSourceFile(root: string): string | undefined { + const found = seedFile(walkedFiles(root)); + return found === undefined ? undefined : join(root, found); +} + +function extensionOf(name: string): string { + const dot = name.lastIndexOf("."); + return dot === -1 ? "" : name.slice(dot); +} + +/** Every project file whose project-relative path is the hint or ends with `/`. */ +export function filesEndingWith(root: string, hint: string): string[] { + return endingWith(walkedFiles(root), hint); +} + +function endingWith(files: readonly string[], hint: string): string[] { + return hintedFiles(files, hint); +} + +/** A wildcard re-export of a whole module: `export * from "./x.ts"`, `export * as ns from …`, `export type * from …`. */ +const WILDCARD_REEXPORT = /^export\s+(?:type\s+)?\*(?:\s+as\s+[A-Za-z_$][A-Za-z0-9_$]*)?\s+from\s*["']([^"']+)["']/; + +/** + * The syntactic form of a reference site, read forward from the top-level + * statement it sits in (ruling d-7abd1ba8). `import` in any shape — plain, + * `import type`, `import * as` — is an import; `export * from`, `export * as + * … from` and an `export { … } from` list are re-exports; a plain + * `export { … }` with no module specifier is neither, and no other statement + * has a form. Reading forward from a statement start is what the dissolved + * heuristic could not do: it scanned backward for a terminator, and a + * semicolon-less bare import gave it none. + */ +export function siteForm(lines: readonly string[], line: number): SiteForm | undefined { + const start = statementStartLine(lines, line); + const head = lines[start] ?? ""; + if (/^import\b(?![(.])/.test(head)) return "import"; + if (/^export\s+(?:type\s+)?\*/.test(head)) return "re-export"; + if (!/^export\s+(?:type\s+)?\{/.test(head)) return undefined; + let joined = ""; + for (let i = start; i < Math.min(lines.length, start + 200); i++) { + const text = lines[i] ?? ""; + joined += (i === start ? "" : "\n") + text; + if (!text.includes("}")) continue; + return /\}\s*from\s*["']/.test(joined) ? "re-export" : undefined; + } + return undefined; +} + +/** Every source file of the project, project-relative, skipping the folders no adopter's code lives in. */ +export function sourceFilesUnder(root: string): string[] { + return walkedFiles(root).filter((rel) => SOURCE_EXTENSIONS.has(extensionOf(rel))); +} + +/** + * Every project-relative file a relative module specifier may name, in the + * order a resolver tries them: the specifier as written, then the TypeScript + * sources it rewrites to (a NodeNext project writes `./foo.js` and means + * `foo.ts`), then the JavaScript ones, then each folder index. Empty when the + * specifier is a package or points outside the project. A caller that can + * test existence takes the first candidate that exists; a caller that keys a + * site by its module keys it by every candidate, since without the file list + * `./foo.js` is `foo.ts` in one project and `foo.js` in the next. + */ +export function specifierCandidates(from: string, specifier: string): string[] { + if (!specifier.startsWith(".")) return []; + const dir = dirname(from); + const base = join(dir, specifier).split(sep).join("/"); + if (base.startsWith("..")) return []; + const stripped = base.replace(/\.(js|jsx|mjs|cjs|ts|tsx|mts|cts)$/, ""); + const candidates = [ + base, + ...[".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"].map((extension) => `${stripped}${extension}`), + ...[".ts", ".tsx", ".js", ".jsx"].flatMap((extension) => [`${stripped}/index${extension}`, `${base}/index${extension}`]), + ]; + return [...new Set(candidates.filter((candidate) => SOURCE_EXTENSIONS.has(extensionOf(candidate))))]; +} + +/** + * The file a relative module specifier names, project-relative: the first + * candidate that `exists`, or without an existence test the first candidate + * at all; undefined when it is a package, points outside, or no candidate + * exists. + */ +export function resolveSpecifier(from: string, specifier: string, exists?: (candidate: string) => boolean): string | undefined { + const candidates = specifierCandidates(from, specifier); + return exists === undefined ? candidates[0] : candidates.find(exists); +} + +function flatten(symbols: DocumentSymbol[], prefix: string[] = []): { path: string[]; symbol: DocumentSymbol }[] { + const out: { path: string[]; symbol: DocumentSymbol }[] = []; + for (const symbol of symbols) { + const path = [...prefix, symbol.name]; + out.push({ path, symbol }); + if (symbol.children !== undefined) out.push(...flatten(symbol.children, path)); + } + return out; +} + +export class TypeScriptAdapter implements LanguageAdapter { + readonly language = "typescript"; + readonly ladder = TYPESCRIPT_LADDER; + private client: JsonRpcClient | undefined; + private starting: Promise<{ ok: true } | { ok: false; reason: string }> | undefined; + private readonly opened = new Set(); + private readonly documents = new Map(); + private readonly symbolCache = new Map(); + private readonly lineCache = new Map(); + /** The document version last sent per open file; a change carries the next one. */ + private readonly versions = new Map(); + /** The first source file, kept open so the project stays loaded. */ + private seed: string | undefined; + /** Files a definition or a reference site landed in since the last forget: the ones a forget re-reads from disk. */ + private readonly touched = new Set(); + /** The unsaved documents a refutation has open right now: the adapter's own probe, never a file, and the one site outside the project's files it accepts. */ + private readonly probes = new Set(); + /** Wildcard re-export sites by the file they re-export; the reference query never reports them. Scanned once per forget. */ + private wildcards: Map | undefined; + /** The project's files and git's listing, each taken once per forget: a name resolved in a file, or a site kept, asks no git between forgets. */ + private walked: string[] | undefined; + private listing: { taken: ProjectListing | undefined } | undefined; + /** The last diagnostics the server published, by project-relative file. */ + private readonly diagnostics = new Map(); + readonly root: string; + + constructor(root: string) { + this.root = resolve(root); + } + + serverPid(): number | undefined { + return this.client?.pid; + } + + ready(): Promise<{ ok: true } | { ok: false; reason: string }> { + this.starting ??= this.start(); + return this.starting; + } + + private async start(): Promise<{ ok: true } | { ok: false; reason: string }> { + const server = locateServer(this.root); + if (!server.found) { + return { ok: false, reason: `${SERVER_BIN} not found; looked at ${server.looked.join("; ")}. Install it: npm install --save-dev typescript-language-server typescript` }; + } + const tsserver = locateTsserver(this.root)?.path; + const client = JsonRpcClient.spawn(server.command, [...server.args, "--stdio"], this.root); + this.client = client; + client.onNotification = (method, params) => { + if (method !== "textDocument/publishDiagnostics") return; + const published = params as { uri?: string; diagnostics?: Diagnostic[] }; + if (published.uri === undefined) return; + this.diagnostics.set(this.relative(published.uri), published.diagnostics ?? []); + }; + try { + await client.request("initialize", { + processId: process.pid, + rootUri: pathToFileURL(this.root).href, + workspaceFolders: [{ uri: pathToFileURL(this.root).href, name: "project" }], + capabilities: { + textDocument: { documentSymbol: { hierarchicalDocumentSymbolSupport: true }, publishDiagnostics: {} }, + workspace: { symbol: {}, workspaceFolders: true }, + }, + initializationOptions: { + // One semantic server only: the syntax server the language server pairs it with by default sees + // open documents alone, and workspace/symbol and references routed there answer for those. + tsserver: { + useSyntaxServer: "never", + ...(tsserver === undefined ? {} : { path: tsserver }), + ...(process.env["COHERENCE_TSSERVER_LOG"] === undefined ? {} : { logDirectory: process.env["COHERENCE_TSSERVER_LOG"], logVerbosity: "verbose" }), + }, + preferences: { includeCompletionsForModuleExports: false }, + }, + }); + client.notify("initialized", {}); + const seed = firstSourceFile(this.root); + this.seed = seed === undefined ? undefined : relative(this.root, seed).split(sep).join("/"); + if (this.seed !== undefined) this.open(this.seed); + return { ok: true }; + } catch (error) { + client.kill(); + this.client = undefined; + return { ok: false, reason: `${SERVER_BIN} at ${server.path} failed to initialize: ${error instanceof Error ? error.message : String(error)}` }; + } + } + + private async live(): Promise { + const state = await this.ready(); + if (!state.ok) throw new Error(state.reason); + if (this.client === undefined || !this.client.alive) { + this.starting = undefined; + this.opened.clear(); + this.versions.clear(); + this.documents.clear(); + const again = await this.ready(); + if (!again.ok) throw new Error(again.reason); + } + return this.client!; + } + + private uri(file: string): string { + return pathToFileURL(join(this.root, file)).href; + } + + private relative(uri: string): string { + return relative(this.root, fileURLToPath(uri)).split(sep).join("/"); + } + + private lines(file: string): string[] { + let lines = this.lineCache.get(file); + if (lines === undefined) { + lines = readFileSync(join(this.root, file), "utf8").split(/\r?\n/); + this.lineCache.set(file, lines); + } + return lines; + } + + private open(file: string, text?: string, identity?: string): void { + if (this.opened.has(file)) return; + const currentIdentity = identity ?? fileIdentity(join(this.root, file)); + const content = text ?? readFileSync(join(this.root, file), "utf8"); + this.client!.notify("textDocument/didOpen", { textDocument: { uri: this.uri(file), languageId: languageIdOf(file), version: 1, text: content } }); + this.opened.add(file); + this.versions.set(file, 1); + this.documents.set(file, { identity: currentIdentity, hash: createHash("sha256").update(content).digest("hex") }); + } + + /** Replace an open document's whole text; the version only ever climbs, so the server never discards a change as old. */ + private change(file: string, text: string, identity = fileIdentity(join(this.root, file))): void { + const version = (this.versions.get(file) ?? 1) + 1; + this.versions.set(file, version); + this.client!.notify("textDocument/didChange", { textDocument: { uri: this.uri(file), version }, contentChanges: [{ text }] }); + this.documents.set(file, { identity, hash: createHash("sha256").update(text).digest("hex") }); + } + + private closeDocument(file: string): void { + if (!this.opened.has(file)) return; + this.client!.notify("textDocument/didClose", { textDocument: { uri: this.uri(file) } }); + this.opened.delete(file); + this.documents.delete(file); + } + + private async documentSymbols(file: string): Promise { + const cached = this.symbolCache.get(file); + if (cached !== undefined) return cached; + // A file the instrument still has in its project but that is no longer on disk has no symbols; + // reading it would throw and take the whole run down with an ENOENT. + if (!existsSync(join(this.root, file))) { + this.symbolCache.set(file, []); + return []; + } + const client = await this.live(); + this.open(file); + const result = await client.request("textDocument/documentSymbol", { textDocument: { uri: this.uri(file) } }); + const symbols: DocumentSymbol[] = (result ?? []).map((s) => + "location" in s ? { name: s.name, kind: s.kind, range: s.location.range, selectionRange: s.location.range } : s, + ); + this.symbolCache.set(file, symbols); + return symbols; + } + + /** + * Cached facts about files are dropped when their text may have changed (the + * edit hook re-runs a check), and the server is made to see the current disk + * text of every document this adapter may have open before any question is + * asked. Closing a document is not enough: tsserver reloads a closed file + * from disk only when it does not own the text, and a didOpen carrying the + * text it already loaded leaves it owning the text, so a close after that + * leaves the edit to its file watcher, which is late under load and blind to + * an excluded file. So every open document whose disk text differs from the + * text last sent, every file touched since the last forget that is not open + * yet, and every file the caller names gets its whole current text (didChange + * for an open document, didOpen for one not yet open, and it stays open), and + * the forget waits for one documentSymbol answer after the last change, which + * the server cannot give before every change is applied. A file that no + * longer exists is closed. + */ + async forget(files: readonly string[] = []): Promise { + this.wildcards = undefined; + this.walked = undefined; + this.listing = undefined; + this.diagnostics.clear(); + if (this.client === undefined) { + this.symbolCache.clear(); + this.lineCache.clear(); + return; + } + // A named file that is not the project's (a nested checkout's copy, an ignored file) is never opened: + // opening it would load another project into the instrument, whose references would then answer as this one's. + const named = keepProjectFiles(this.root, files); + const forced = new Set(files.filter((file) => named.has(file))); + const refresh = new Set([...this.touched, ...forced, ...this.opened]); + this.touched.clear(); + let lastSyncedFile: string | undefined; + const unchangedFiles = new Set(); + for (const file of refresh) { + const identity = fileIdentity(join(this.root, file)); + if (identity === undefined) { + this.closeDocument(file); + continue; + } + const isForced = forced.has(file); + if (!isForced && this.documents.get(file)?.identity === identity) { + unchangedFiles.add(file); + continue; + } + const text = readFileSync(join(this.root, file), "utf8"); + const hash = createHash("sha256").update(text).digest("hex"); + if (!isForced && this.documents.get(file)?.hash === hash) { + this.documents.set(file, { identity, hash }); + unchangedFiles.add(file); + continue; + } + lastSyncedFile = file; + if (this.opened.has(file)) { + this.change(file, text, identity); + continue; + } + this.open(file, text, identity); + } + // An open document whose text the server already holds keeps its symbols and lines; every other file is read again. + for (const file of [...this.symbolCache.keys()]) if (!unchangedFiles.has(file)) this.symbolCache.delete(file); + for (const file of [...this.lineCache.keys()]) if (!unchangedFiles.has(file)) this.lineCache.delete(file); + if (lastSyncedFile !== undefined) await this.documentSymbols(lastSyncedFile); + } + + async resolve(name: string, hint: ResolveHint): Promise { + const parsed = parseName(name); + if (parsed.form === "prose") { + return { ok: false, reason: `"${name}" is prose, not a symbol or a module; write the symbol (\`writeClass\`), the symbol in its file (\`KERNEL_WRITE_POLICY in policy.ts\`), or the module path` }; + } + if (parsed.form === "module") { + const path = join(this.root, parsed.path); + if (!existsSync(path) || !statSync(path).isFile()) return { ok: false, reason: `module ${parsed.path} is not a file under the project` }; + if (!keepProjectFiles(this.root, [parsed.path]).has(parsed.path)) return { ok: false, reason: `module ${parsed.path} is not one of the project's files (ignored, or inside a nested checkout)` }; + const lines = this.lines(parsed.path); + const symbols = await this.documentSymbols(parsed.path); + const first = symbols.find((s) => this.exportedIn(parsed.path, s)); + return { + ok: true, + definition: { + name, + kind: "module", + file: parsed.path, + range: { start: { line: 0, character: 0 }, end: { line: Math.max(0, lines.length - 1), character: (lines[lines.length - 1] ?? "").length } }, + selection: first?.selectionRange.start ?? { line: 0, character: 0 }, + }, + }; + } + const candidates = parsed.fileHint === undefined ? await this.searchWorkspace(parsed.name) : await this.searchFiles(parsed.name, parsed.fileHint); + if (candidates.length === 0) { + return { ok: false, reason: parsed.fileHint === undefined ? `no symbol named ${parsed.name} in the project` : `no symbol named ${parsed.name} in a file ending with ${parsed.fileHint}` }; + } + const chosen = choose(candidates, hint); + if (chosen === undefined) { + const where = candidates.map((c) => `${c.file}:${c.symbol.selectionRange.start.line + 1}`); + return { ok: false, reason: `${parsed.name} is declared in ${candidates.length} places; write \`${parsed.name} in \``, candidates: where }; + } + return { + ok: true, + definition: { name, kind: "symbol", file: chosen.file, range: chosen.symbol.range, selection: chosen.symbol.selectionRange.start }, + }; + } + + private async searchWorkspace(name: string): Promise { + const client = await this.live(); + const found = await client.request("workspace/symbol", { query: name }); + const files = new Set(); + for (const info of found ?? []) { + if (info.name !== name) continue; + const file = this.relative(info.location.uri); + if (file.startsWith("..") || file.startsWith("node_modules/")) continue; + files.add(file); + } + const own = keepProjectFiles(this.root, [...files], this.listingNow()); + const candidates: Candidate[] = []; + for (const file of [...files].filter((f) => own.has(f)).sort()) candidates.push(...(await this.declarationsIn(file, name))); + if (candidates.length > 0) return candidates; + // The server searches only the projects it has loaded: a name it does not know yet (a cold server, a second tsconfig) is + // looked for in the files whose text spells it, and confirmed by their document symbols, never by the text alone. + const spelled = new RegExp(`(^|[^\\w$])${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}([^\\w$]|$)`); + for (const file of projectSources(this.walkedNow())) { + let text: string; + try { + text = readFileSync(join(this.root, file), "utf8"); + } catch { + continue; + } + if (spelled.test(text)) candidates.push(...(await this.declarationsIn(file, name))); + } + return candidates; + } + + private async searchFiles(name: string, fileHint: string): Promise { + const candidates: Candidate[] = []; + for (const file of endingWith(this.walkedNow(), fileHint)) candidates.push(...(await this.declarationsIn(file, name))); + return candidates; + } + + /** The project's files as the walk reads them, taken once per forget. */ + private walkedNow(): string[] { + return (this.walked ??= walkedFiles(this.root)); + } + + /** Git's listing of the project, taken once per forget. */ + private listingNow(): ProjectListing | undefined { + return (this.listing ??= { taken: projectListing(this.root) }).taken; + } + + /** Top-level declarations named `name` in a file (a nested declaration is not a module member). */ + private async declarationsIn(file: string, name: string): Promise { + const symbols = await this.documentSymbols(file); + return symbols.filter((s) => s.name === name).map((symbol) => ({ file, symbol })); + } + + async references(definition: Definition): Promise { + const client = await this.live(); + this.open(definition.file); + this.touched.add(definition.file); + this.openHorizon(); + const starts: Position[] = []; + if (definition.kind === "module") { + for (const symbol of await this.documentSymbols(definition.file)) { + if (this.exportedIn(definition.file, symbol)) starts.push(symbol.selectionRange.start); + } + } else { + starts.push(definition.selection); + } + const reported: Location[] = []; + for (const position of starts) { + const locations = await client.request("textDocument/references", { + textDocument: { uri: this.uri(definition.file) }, + position, + context: { includeDeclaration: false }, + }); + reported.push(...(locations ?? [])); + } + // Only the project's own files and its reference horizon's are evidence, and a site outside them is dropped before it is read or + // opened: opening a nested checkout's copy would load that checkout into the instrument as if it were this project. + const own = keepHorizonFiles(this.root, reported.map((location) => this.relative(location.uri)), this.listingNow(), this.horizon()); + const seen = new Set(); + const sites: ReferenceSite[] = []; + for (const location of reported) { + const file = this.relative(location.uri); + if (!(own.has(file) || this.probes.has(file)) || file.startsWith("node_modules/")) continue; + const start = location.range.start; + if (file === definition.file && rangeContains({ start: definition.selection, end: definition.selection }, start)) continue; + const key = `${file}:${start.line}:${start.character}`; + if (seen.has(key)) continue; + seen.add(key); + this.touched.add(file); + const form = siteForm(this.linesOf(file), start.line); + sites.push({ file, line: start.line + 1, character: start.character, symbol: await this.enclosingSymbol(file, start), ...(form === undefined ? {} : { form }) }); + } + // A wildcard re-export names nothing, so the server reports no site for it; it still widens the thing's reach. + if (definition.kind === "module" || (await this.visibility(definition)).visible) { + for (const site of this.wildcardReExports(definition.file)) { + const key = `${site.file}:${site.line - 1}:${site.character}`; + if (seen.has(key)) continue; + seen.add(key); + this.touched.add(site.file); + sites.push(site); + } + } + sites.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.character - b.character); + return sites; + } + + /** The folders outside the project the config's `references` adds to the search, absolute; read once. */ + private horizonAt: string[] | undefined; + private horizon(): string[] { + return (this.horizonAt ??= horizonFolders(this.root)); + } + + /** + * Load each horizon folder into the server: every source file git lists + * there outside the project is opened, so the server holds the projects + * they belong to (a tsconfig's, or the inferred one for loose files) and a + * references query searches them too. Once per adapter; the cost grows + * with the folders the config names, which is why the default is none. + */ + private horizonOpened = false; + private openHorizon(): void { + if (this.horizonOpened) return; + this.horizonOpened = true; + for (const folder of this.horizon()) { + for (const rel of walkedFiles(folder)) { + if (!SOURCE_EXTENSIONS.has(extensionOf(rel)) || /\.d\.ts$/.test(rel)) continue; + const file = relative(this.root, join(folder, rel)).split(sep).join("/"); + if (file.startsWith("../")) this.open(file); + } + } + } + + /** The sites where another module re-exports this file wholesale, scanned once per forget because the reference query never reports them. */ + private wildcardReExports(file: string): ReferenceSite[] { + if (this.wildcards === undefined) { + const walked = new Set(this.walkedNow()); + const found = new Map(); + for (const source of sourceFilesUnder(this.root)) { + let lines: string[]; + try { + lines = readFileSync(join(this.root, source), "utf8").split(/\r?\n/); + } catch { + continue; + } + for (let i = 0; i < lines.length; i++) { + const match = WILDCARD_REEXPORT.exec(lines[i] ?? ""); + if (match === null) continue; + const target = resolveSpecifier(source, match[1]!, (candidate) => walked.has(candidate)); + if (target === undefined) continue; + const list = found.get(target) ?? []; + list.push({ file: source, line: i + 1, character: (lines[i] ?? "").indexOf("*"), symbol: undefined, form: "re-export" }); + found.set(target, list); + } + } + this.wildcards = found; + } + return this.wildcards.get(file) ?? []; + } + + private linesOf(file: string): string[] { + try { + return this.lines(file); + } catch { + return []; + } + } + + private async enclosingSymbol(file: string, position: Position): Promise { + let symbols: DocumentSymbol[]; + try { + symbols = await this.documentSymbols(file); + } catch { + return undefined; + } + let best: { path: string[]; symbol: DocumentSymbol } | undefined; + for (const entry of flatten(symbols)) { + if (!rangeContains(entry.symbol.range, position)) continue; + if (best === undefined || entry.path.length > best.path.length) best = entry; + } + return best?.path.join("."); + } + + private exportedIn(file: string, symbol: DocumentSymbol): boolean { + return this.visibilityOf(file, symbol.name, symbol.range.start.line).visible; + } + + private visibilityOf(file: string, name: string, declarationLine: number): Visibility { + const lines = this.linesOf(file); + const declaration = (lines[declarationLine] ?? "").trim(); + if (/^export\b/.test(declaration)) return { enforced: true, visible: true, evidence: `${file}:${declarationLine + 1} reads "${declaration.slice(0, 60)}"` }; + const listed = new RegExp(`export\\s*(type\\s*)?\\{[^}]*\\b${name}\\b[^}]*\\}`); + const asDefault = new RegExp(`export\\s+default\\s+${name}\\b`); + for (let i = 0; i < lines.length; i++) { + const text = lines[i]!; + if (listed.test(text) || asDefault.test(text)) return { enforced: true, visible: true, evidence: `${file}:${i + 1} exports ${name}` }; + } + return { enforced: true, visible: false, evidence: `${file}:${declarationLine + 1} declares ${name} without export and no export list names it` }; + } + + async visibility(definition: Definition, _chokepoint?: Definition): Promise { + if (definition.kind === "module") { + return { enforced: true, visible: true, evidence: `${definition.file} is a module; any file may import it` }; + } + const name = await this.declaredName(definition); + if (name === undefined) return { enforced: true, visible: false, evidence: `no declaration at ${definition.file}:${definition.selection.line + 1}` }; + return this.visibilityOf(definition.file, name, definition.range.start.line); + } + + /** The name as declared at the definition's selection, which the spec may have written with a file hint. */ + private async declaredName(definition: Definition): Promise { + const symbols = await this.documentSymbols(definition.file); + return symbols.find((s) => s.selectionRange.start.line === definition.selection.line && s.selectionRange.start.character === definition.selection.character)?.name; + } + + testFilter(via: string): string { + return via; + } + + /** + * Two rulings meet here. For a thing the compiler will not let any other + * module name, the compiler's own refusal of a synthetic outside import is + * the refutation (rs-e93ecdd6). For everything else, the refutation stages + * the two sites the import ruling could otherwise swallow (d-7abd1ba8): a + * use of the thing in the chokepoint's own module outside the chokepoint's + * range, and a re-export of it from a document beside it. The adapter only + * reports what the instrument said about each; the check classifies them. + */ + async refute(protectedThing: Definition, outsideOf: Definition | undefined, exempt?: string): Promise { + const client = await this.live(); + const symbols = await this.documentSymbols(protectedThing.file); + let name: string | undefined; + if (protectedThing.kind === "module") { + name = symbols.find((s) => this.exportedIn(protectedThing.file, s))?.name; + if (name === undefined) return { seen: false, staged: [], account: `${protectedThing.file} exports nothing, so no document can reference it` }; + } else { + name = await this.declaredName(protectedThing); + if (name === undefined) return { seen: false, staged: [], account: `no declaration at ${protectedThing.file}:${protectedThing.selection.line + 1}` }; + if (!this.visibilityOf(protectedThing.file, name, protectedThing.range.start.line).visible) return this.refusedByCompiler(client, protectedThing, name); + } + return this.stage(client, protectedThing, outsideOf, name, exempt); + } + + /** The compiler refuses an import of a thing its module does not export: open the synthetic outside document and read the diagnostic back. */ + private async refusedByCompiler(client: JsonRpcClient, protectedThing: Definition, name: string): Promise { + const dir = dirname(protectedThing.file); + const base = protectedThing.file.slice(dir === "." ? 0 : dir.length + 1); + const synthetic = `${dir === "." ? "" : dir + "/"}coherence-refutation-${randomBytes(4).toString("hex")}${syntheticExtensionBeside(protectedThing.file)}`; + // A JavaScript document is type-checked only under checkJs or `// @ts-check`; without it the compiler publishes no + // diagnostic, and the refusal an ES module's link would raise is never seen. The probe asks for the check itself. + const checked = JAVASCRIPT_EXTENSIONS.has(extensionOf(synthetic)) ? "// @ts-check\n" : ""; + const text = `${checked}import { ${name} } from "./${base}";\nexport const coherenceRefutation = ${name};\n`; + this.diagnostics.delete(synthetic); + client.notify("textDocument/didOpen", { textDocument: { uri: this.uri(synthetic), languageId: languageIdOf(synthetic), version: 1, text } }); + this.lineCache.set(synthetic, text.split("\n")); + this.symbolCache.set(synthetic, []); + try { + const refusal = await this.awaitRefusal(synthetic); + if (refusal !== undefined) { + return { + seen: true, + staged: [], + refused: refusal, + account: `an unsaved document ${synthetic} importing ${name} was refused by the compiler: ${refusal}`, + }; + } + return { seen: false, staged: [], account: `an unsaved document ${synthetic} importing ${name} drew no diagnostic from the compiler, so nothing proves the import is refused` }; + } finally { + client.notify("textDocument/didClose", { textDocument: { uri: this.uri(synthetic) } }); + this.lineCache.delete(synthetic); + this.symbolCache.delete(synthetic); + this.diagnostics.delete(synthetic); + } + } + + /** The first published diagnostic on a file that refuses the reference, within the window; the server publishes an empty set first. */ + private async awaitRefusal(file: string, timeoutMs = 15_000): Promise { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + const refusal = (this.diagnostics.get(file) ?? []).find((d) => refusesReference(d)); + if (refusal !== undefined) return refusal.message; + await new Promise((resolve) => setTimeout(resolve, 50)); + } + return undefined; + } + + /** Stage the two synthetic sites the import ruling could otherwise swallow, in one references query, and restore. */ + private async stage(client: JsonRpcClient, protectedThing: Definition, chokepoint: Definition | undefined, name: string, exempt?: string): Promise { + const dir = dirname(protectedThing.file); + const base = protectedThing.file.slice(dir === "." ? 0 : dir.length + 1); + const synthetic = `${dir === "." ? "" : dir + "/"}coherence-refutation-${randomBytes(4).toString("hex")}${syntheticExtensionBeside(protectedThing.file)}`; + const reExport = `export { ${name} } from "./${base}";\n`; + client.notify("textDocument/didOpen", { textDocument: { uri: this.uri(synthetic), languageId: languageIdOf(synthetic), version: 1, text: reExport } }); + this.lineCache.set(synthetic, reExport.split("\n")); + this.symbolCache.set(synthetic, []); + this.probes.add(synthetic); + + // A module chokepoint has no inside that is outside its own range, so there is no same-module site to stage; + // nor is there where the exempted folder holds the chokepoint's module, which the exemption covers on purpose. + const exempted = exempt !== undefined && chokepoint !== undefined && withinFolder(chokepoint.file, exempt); + const sameModule = chokepoint !== undefined && chokepoint.kind === "symbol" && !exempted ? this.editChokepointModule(chokepoint, protectedThing, name) : undefined; + const expected: { what: string; file: string; line: number }[] = []; + if (sameModule !== undefined) expected.push({ what: `a use of ${name} in ${chokepoint!.file} outside ${chokepoint!.name}`, file: chokepoint!.file, line: sameModule.line }); + expected.push({ what: `a re-export of ${name} from the unsaved document ${synthetic}`, file: synthetic, line: 1 }); + // Where the chokepoint governs only references from outside a folder, a plain use from outside it must still be a bypass. + const beside = exempt === undefined ? undefined : outsideOfFolder(exempt); + const outside = beside === undefined ? undefined : `${beside}coherence-refutation-${randomBytes(4).toString("hex")}${syntheticExtensionBeside(protectedThing.file)}`; + if (outside !== undefined) { + const specifier = `./${relative(dirname(outside), protectedThing.file).split(sep).join("/")}`.replace(/^\.\/\.\.\//, "../"); + const use = `import { ${name} as coherenceRefutationName } from "${specifier}";\nexport const coherenceRefutationUse = coherenceRefutationName;\n`; + client.notify("textDocument/didOpen", { textDocument: { uri: this.uri(outside), languageId: languageIdOf(outside), version: 1, text: use } }); + this.lineCache.set(outside, use.split("\n")); + this.symbolCache.set(outside, []); + this.probes.add(outside); + expected.push({ what: `a use of ${name} from the unsaved document ${outside}, outside ${exempt}`, file: outside, line: 2 }); + } + + try { + const sites = await this.references(protectedThing); + const staged: StagedSite[] = expected.map((want) => { + const hit = sites.find((s) => s.file === want.file && s.line === want.line); + return { what: want.what, ...(hit === undefined ? {} : { site: hit }) }; + }); + const unseen = staged.filter((s) => s.site === undefined); + return { + seen: unseen.length === 0, + staged, + account: + unseen.length === 0 + ? `the instrument reported ${staged.map((s) => s.what).join(" and ")}` + : `the instrument did not report ${unseen.map((s) => s.what).join(" or ")} among ${sites.length} references; the check is vacuous`, + }; + } finally { + sameModule?.restore(); + for (const file of outside === undefined ? [synthetic] : [synthetic, outside]) { + client.notify("textDocument/didClose", { textDocument: { uri: this.uri(file) } }); + this.lineCache.delete(file); + this.symbolCache.delete(file); + this.probes.delete(file); + } + } + } + + /** + * Append a use of the protected thing to the chokepoint's own module, past + * the chokepoint's range, as an unsaved edit: the one place the import + * ruling makes an import inside, so the one place a use must still be a + * bypass. When the module reaches the thing through an import, the added + * lines bring their own aliased import, so the use never collides with a + * binding already there. + */ + private editChokepointModule(chokepoint: Definition, protectedThing: Definition, name: string): { line: number; restore: () => void } | undefined { + let original: string; + try { + original = readFileSync(join(this.root, chokepoint.file), "utf8"); + } catch { + return undefined; + } + const body = original.endsWith("\n") ? original : `${original}\n`; + const start = body.split("\n").length - 1; + const here = dirname(chokepoint.file); + const specifier = `./${relative(here, protectedThing.file).split(sep).join("/")}`.replace(/^\.\/\.\.\//, "../"); + const added = + chokepoint.file === protectedThing.file + ? `const coherenceRefutationUse = ${name};\n` + : `import { ${name} as coherenceRefutationName } from "${specifier}";\nconst coherenceRefutationUse = coherenceRefutationName;\n`; + const line = start + (chokepoint.file === protectedThing.file ? 1 : 2); + this.open(chokepoint.file); + this.change(chokepoint.file, body + added); + this.symbolCache.delete(chokepoint.file); + this.lineCache.set(chokepoint.file, (body + added).split("\n")); + return { + line, + restore: () => { + this.change(chokepoint.file, original); + this.symbolCache.delete(chokepoint.file); + this.lineCache.delete(chokepoint.file); + }, + }; + } + + async close(): Promise { + const client = this.client; + this.client = undefined; + this.starting = undefined; + if (client === undefined) return; + try { + await client.request("shutdown", null, 3_000); + client.notify("exit", null); + } catch { + // The server is going down either way. + } + setTimeout(() => client.kill(), 500).unref(); + } +} + +interface Candidate { + file: string; + symbol: DocumentSymbol; +} + +/** One candidate: the only one, else the only one under the component, else the only one outside test folders; ambiguity is reported, never guessed. */ +function choose(candidates: Candidate[], hint: ResolveHint): Candidate | undefined { + if (candidates.length === 1) return candidates[0]; + const nonTest = candidates.filter((c) => !isTestPath(c.file, hint.testFolders)); + if (nonTest.length === 1) return nonTest[0]; + const pool = nonTest.length > 0 ? nonTest : candidates; + const prefix = hint.component === "." ? "" : hint.component + "/"; + const under = pool.filter((c) => c.file.startsWith(prefix)); + if (under.length === 1) return under[0]; + return undefined; +} diff --git a/src/plugins/fixtures/parser-plugin.ts b/src/plugins/fixtures/parser-plugin.ts new file mode 100644 index 00000000..3c3bab39 --- /dev/null +++ b/src/plugins/fixtures/parser-plugin.ts @@ -0,0 +1,36 @@ +/** + * A plugin folder for the plugin interface's tests that reads a made-up + * language, "zz", through Python's tree-sitter parser and queries: the one + * way a plugin reads its language's text (docs/plugins.md, Reading through a + * parser), so a test that needs a language the core reads uses this, never a + * hand-written reader, which no plugin may fill. + */ + +import { copyFileSync, mkdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { PLUGIN_API, type PluginManifest } from "../plugin.ts"; +import { BUNDLED_DIR } from "../registry.ts"; + +/** Where an import leads (nowhere), and an interfaces table that states only the language's own facts. */ +export const PARSER_RESOLVE = "export const RESOLVE = { resolveModule: () => undefined, modulePaths: () => [] };\nexport const FACTS = { serverBounds: false };\n"; + +/** + * Write the plugin into `dir`: Python's parser as zz.wasm and its queries as + * zz.scm, a resolve that leads nowhere, an empty module, and a manifest for + * the current pluginApi, each overridden by `manifest` and `files`. + */ +export function writeParserPlugin(dir: string, manifest: Record = {}, files: Record = {}): PluginManifest { + mkdirSync(dir, { recursive: true }); + const python = join(BUNDLED_DIR, "python"); + copyFileSync(join(python, "tree-sitter-python.wasm"), join(dir, "zz.wasm")); + copyFileSync(join(python, "python.scm"), join(dir, "zz.scm")); + writeFileSync(join(dir, "resolve.ts"), PARSER_RESOLVE); + writeFileSync(join(dir, "index.ts"), "export default {};\n"); + for (const [name, text] of Object.entries(files)) { + mkdirSync(join(dir, name, ".."), { recursive: true }); + writeFileSync(join(dir, name), text); + } + const full = { name: "zz", version: "0.1.0", pluginApi: PLUGIN_API, provides: { language: "zz" }, extensions: [".zz"], module: "./index.ts", treeSitter: { parser: "zz.wasm", queries: "zz.scm", resolve: "resolve.ts#RESOLVE" }, ...manifest }; + writeFileSync(join(dir, "plugin.json"), JSON.stringify(full)); + return full as PluginManifest; +} diff --git a/src/plugins/go.test.ts b/src/plugins/go.test.ts index 91814f8d..4ee631c0 100644 --- a/src/plugins/go.test.ts +++ b/src/plugins/go.test.ts @@ -9,12 +9,22 @@ */ import assert from "node:assert/strict"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; import { test } from "node:test"; -import { goDeclaresAtTop } from "../../plugins/go/go-top-level.ts"; +import { readEnforcementConfig } from "../enforcement/config.ts"; import { locateGopls } from "../../plugins/go/go.ts"; import { checkPlugin } from "./check.ts"; +import { parsedOf } from "./languages.ts"; test("Go's top level is read by its slot: a func, a type, a var or const alone or grouped is declared; a method, a local and another package's name are not", () => { + // A project that names the Go plugin, so its slots answer for "go": the topLevel slot is derived from its parser. + const root = mkdtempSync(join(tmpdir(), "coherence-go-top-level-")); + writeFileSync(join(root, "coherence.config.json"), JSON.stringify({ language: "go", plugins: { go: "bundled" } })); + readEnforcementConfig(root); + rmSync(root, { recursive: true, force: true }); + const goDeclaresAtTop = parsedOf("go", "topLevel")!; const text = [ "package store", "", @@ -49,6 +59,6 @@ test("plugin check holds the Go plugin to every duty a language plugin owes, rea assert.ok(gopls.found, `gopls is not installed, so the Go plugin's duties cannot be read: go install golang.org/x/tools/gopls@v0.23.0 (looked at: ${gopls.found ? "" : gopls.looked.join("; ")})`); const checked = await checkPlugin(process.cwd(), "go"); assert.equal(checked.language, "go"); - assert.deepEqual(checked.duties.map((d) => [d.name, d.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["references", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"]], JSON.stringify(checked.duties)); - assert.match(checked.duties[3]!.reason, /SecretColumns through Seal graded broken, refutation automatic/); + assert.deepEqual(checked.duties.map((d) => [d.name, d.verdict]), [["file rule", "pass"], ["declarations", "pass"], ["answers agree", "pass"], ["reference reading", "pass"], ["references", "pass"], ["server agrees", "pass"], ["chokepoint", "pass"], ["mass", "pass"], ["imports", "pass"], ["interfaces", "pass"], ["entrances", "pass"], ["one answer each", "pass"]], JSON.stringify(checked.duties)); + assert.match(checked.duties.find((d) => d.name === "chokepoint")!.reason, /SecretColumns through Seal graded broken, refutation automatic/); }); diff --git a/src/plugins/languages.test.ts b/src/plugins/languages.test.ts index 80ad78e5..9ddce413 100644 --- a/src/plugins/languages.test.ts +++ b/src/plugins/languages.test.ts @@ -20,7 +20,8 @@ import { instrumentFor } from "../adapters/index.ts"; import { readEnforcementConfig } from "../enforcement/config.ts"; import { BUNDLED_DIR, moduleOf, moduleSyncOf } from "./registry.ts"; import { moduleSpecifiers } from "./specifiers.ts"; -import { ciNotes, ciSteps, entranceRules, environmentFolders, forProject, LANGUAGES, languageOfFile, providerOf, serverExtensions, syntaxOf } from "./languages.ts"; +import { writeParserPlugin } from "./fixtures/parser-plugin.ts"; +import { ciNotes, ciSteps, entranceRules, environmentFolders, forProject, LANGUAGES, languageOfFile, parsedOf, providerOf, serverExtensions, syntaxOf } from "./languages.ts"; import { loadSpecModel } from "../spec/model.ts"; const SRC = resolve(dirname(fileURLToPath(import.meta.url)), ".."); @@ -134,7 +135,7 @@ test("a project with no plugins key reads every language through the bundled plu for (const language of LANGUAGES) assert.equal(providerOf(language)?.dir, join(BUNDLED_DIR, language), `${language} is the bundled plugin's`); assert.deepEqual(["a.ts", "a.d.ts", "b.pyi", "c.rs", "d.swift"].map((f) => languageOfFile(f) ?? null), ["typescript", null, "python", "rust", null], "which files are a language's is each plugin's manifest data"); assert.equal(instrumentFor("python", bare, config).constructor.name, "PythonAdapter", "the adapter is the bundled plugin's"); - assert.equal(typeof syntaxOf("typescript", "source")?.declarationOf, "function"); + assert.equal(typeof parsedOf("typescript", "source")?.importsOf, "function"); const swapped = project({ "coherence.config.json": JSON.stringify({ language: ["python"], plugins: { py: "./plugins/py" } }), @@ -144,7 +145,7 @@ test("a project with no plugins key reads every language through the bundled plu readEnforcementConfig(swapped); assert.equal(providerOf("python")?.name, "py", "the project's plugin takes python's place"); assert.equal(languageOfFile("x.py"), "python", "its files are the bundled plugin's, which it does not restate"); - assert.equal(typeof syntaxOf("python", "source")?.declarationOf, "function", "the bundled plugin's source scan stands behind it"); + assert.equal(typeof parsedOf("python", "source")?.importsOf, "function", "the bundled plugin's source scan stands behind it"); assert.ok(isTestPath("src/check_x.py", []), "a field it declares is its own"); assert.ok(!isTestPath("src/test_x.py", []), "and replaces the bundled plugin's"); readEnforcementConfig(bare); @@ -167,30 +168,29 @@ test("a plugin's testFolders name the folders its language keeps tests in, by ex }); test("a plugin that provides a language no bundled plugin does is read as a bundled one is, for its project alone: its files, tests, folders, entrance rules, CI steps and syntax slots; a language nothing provides is refused by the spec check as by a run", () => { - const zz = (fields: Record = {}): Record => ({ - "plugins/zz/plugin.json": JSON.stringify({ - name: "zz", - version: "0.1.0", - pluginApi: 2, - provides: { language: "zz" }, - module: "./index.ts", - extensions: [".zz"], - testFiles: ["_check\\.zz$"], - environmentFolders: ["zzdeps"], - entrances: { rules: [{ rule: "zz verb", plural: "zz verbs", detects: "a verb a zz file exports" }], notDetected: "a zz verb built at run time" }, - ci: { note: "zz needs its server", steps: [{ name: "zz server", run: "install-zz-server" }] }, - syntax: { topLevel: "top.ts#zzDeclaresAtTop" }, - ...fields, + // Read through a parser (Python's, as zz), with every manifest field and a syntax slot no parse answers (notice). + const zz = (root: string, fields: Record = {}): string => { + writeParserPlugin( + join(root, "plugins/zz"), + { + testFiles: ["_check\\.zz$"], + environmentFolders: ["zzdeps"], + entrances: { rules: [{ rule: "zz verb", plural: "zz verbs", detects: "a verb a zz file exports" }], notDetected: "a zz verb built at run time" }, + ci: { note: "zz needs its server", steps: [{ name: "zz server", run: "install-zz-server" }] }, + syntax: { notice: "notice.ts#zzNotice" }, + ...fields, + }, + { "index.ts": swapPlugin("zz", "zz", {})["plugins/zz/index.ts"]!, "notice.ts": 'export const zzNotice = () => "zz reads through its parser";\n' }, + ); + return root; + }; + const root = zz( + project({ + "coherence.config.json": JSON.stringify({ language: ["zz"], plugins: { zz: "./plugins/zz" } }), + "app/Accounts.spec.md": "# Accounts\n\nThe accounts.\n\n## entrances\n- reset: an operator resets a password\n handler: reset in app/accounts.zz\n- rename: an operator renames an account\n handler: rename in app/accounts.zz\n", + "app/accounts.zz": "def reset():\n pass\n", }), - "plugins/zz/index.ts": swapPlugin("zz", "zz", {})["plugins/zz/index.ts"]!, - "plugins/zz/top.ts": "export const zzDeclaresAtTop = (text, name) => text.split(\"\\n\").includes(`verb ${name}`);\n", - }); - const root = project({ - "coherence.config.json": JSON.stringify({ language: ["zz"], plugins: { zz: "./plugins/zz" } }), - ...zz(), - "app/Accounts.spec.md": "# Accounts\n\nThe accounts.\n\n## entrances\n- reset: an operator resets a password\n handler: reset in app/accounts.zz\n- rename: an operator renames an account\n handler: rename in app/accounts.zz\n", - "app/accounts.zz": "verb reset\n", - }); + ); const config = readEnforcementConfig(root); assert.deepEqual(config.languages, ["zz"], "the plugin's language is among those the readings read, not set aside as unscanned"); assert.doesNotThrow(() => readEnforcementConfig(root), "reading the config again never takes the plugin for another owner of its own .zz"); @@ -199,18 +199,19 @@ test("a plugin that provides a language no bundled plugin does is read as a bund assert.ok(environmentFolders().has("zzdeps"), "its environment folders are left out of every walk"); assert.deepEqual(entranceRules("zz").map((r) => r.rule), ["zz verb"], "its entrance rules are the language's"); assert.deepEqual([ciNotes(["zz"]), ciSteps(["zz"])], [["zz needs its server"], [{ name: "zz server", run: "install-zz-server" }]], "the CI workflow carries its note and its steps"); - const topLevel = syntaxOf("zz", "topLevel"); - assert.ok(typeof topLevel === "function" && topLevel("verb reset\n", "reset"), "its syntax slot answers for it"); + assert.equal(syntaxOf("zz", "notice")?.(root), "zz reads through its parser", "its syntax slot answers for it"); + const topLevel = parsedOf("zz", "topLevel"); + assert.ok(typeof topLevel === "function" && topLevel("def reset():\n pass\n", "reset"), "and its parser reads its text"); const problems = loadSpecModel(root, { runs: false }).problems.map((p) => p.message).filter((m) => /entrance/.test(m)); assert.equal(problems.length, 1, JSON.stringify(problems)); - assert.match(problems[0]!, /entrance rename: handler rename is not declared at the top level of app\/accounts\.zz/, "the spec check reads its handlers by the plugin's slot: one declared, one not"); + assert.match(problems[0]!, /entrance rename: handler rename is not declared at the top level of app\/accounts\.zz/, "the spec check reads its handlers through the plugin's parser: one declared, one not"); const bare = project({ "coherence.config.json": JSON.stringify({ language: "typescript" }) }); readEnforcementConfig(bare); assert.equal(languageOfFile("app/accounts.zz"), undefined, "a project that does not name the plugin reads none of it"); assert.equal(forProject(root, () => languageOfFile("app/accounts.zz")), "zz", "while the one that does still reads it"); - const taken = project({ "coherence.config.json": JSON.stringify({ language: ["zz"], plugins: { zz: "./plugins/zz" } }), ...zz({ extensions: [".zz", ".py"] }) }); + const taken = zz(project({ "coherence.config.json": JSON.stringify({ language: ["zz"], plugins: { zz: "./plugins/zz" } }) }), { extensions: [".zz", ".py"] }); assert.throws(() => readEnforcementConfig(taken), /plugin zz claims \.py, which python already reads/, "a bundled language's files are never a new language's"); const unnamed = project({ "coherence.config.json": JSON.stringify({ language: "zz" }) }); @@ -279,11 +280,11 @@ test("a session start names each plugin the project brings whose syntax code run const { startReading } = await import("../lifecycle/hook.ts"); const withSyntax = project({ "coherence.config.json": JSON.stringify({ language: "python", plugins: { pyx: "./plugins/pyx" } }), - ...swapPlugin("pyx", "python", { syntax: { source: "source.ts#SOURCE" } }), - "plugins/pyx/source.ts": "export const SOURCE = { declarationOf: () => undefined, resolveModule: () => undefined, importsOf: () => {} };\n", + ...swapPlugin("pyx", "python", { syntax: { notice: "notice.ts#NOTICE" } }), + "plugins/pyx/notice.ts": 'export const NOTICE = () => "";\n', }); const said = (await startReading(withSyntax)).text; - assert.match(said, /^Plugin code in this session's hooks: pyx \(\.\/plugins\/pyx: source\) runs as a reading reads its language, with the project's privileges\.$/m, said); + assert.match(said, /^Plugin code in this session's hooks: pyx \(\.\/plugins\/pyx: notice\) runs as a reading reads its language, with the project's privileges\.$/m, said); assert.equal(said.match(/Plugin code in this session's hooks/g)?.length, 1, "one line"); const adapterOnly = project({ "coherence.config.json": JSON.stringify({ language: "python", plugins: { pyx: "./plugins/pyx" } }), ...swapPlugin("pyx", "python", {}) }); assert.doesNotMatch((await startReading(adapterOnly)).text, /Plugin code in this session's hooks/, "a plugin whose code runs only in a run and the warm server"); @@ -293,14 +294,14 @@ test("a session start names each plugin the project brings whose syntax code run test("a session start names each plugin written for an older pluginApi with what changed since, in one line, and nothing for one on the current interface", async () => { const { startReading } = await import("../lifecycle/hook.ts"); - const { PLUGIN_API } = await import("./plugin.ts"); + const { PLUGIN_API, PLUGIN_API_CHANGES } = await import("./plugin.ts"); const at = (pluginApi: number): string => project({ "coherence.config.json": JSON.stringify({ language: "python", plugins: { pyx: "./plugins/pyx" } }), ...swapPlugin("pyx", "python", { pluginApi }), }); const older = (await startReading(at(PLUGIN_API - 1))).text; - assert.match(older, new RegExp(`^Plugins written for an older pluginApi \\(this Coherence runs ${PLUGIN_API}\\): pyx \\(${PLUGIN_API - 1}; since: ${PLUGIN_API}: syntax slots moved from the module's syntax export to plugin\\.json[^\\n]*\\)\\.$`, "m"), older); + assert.match(older, new RegExp(`^Plugins written for an older pluginApi \\(this Coherence runs ${PLUGIN_API}\\): pyx \\(${PLUGIN_API - 1}; since: ${PLUGIN_API}: ${PLUGIN_API_CHANGES[PLUGIN_API]!.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\)\\.$`, "m"), older); assert.equal(older.match(/older pluginApi/g)?.length, 1, "one line"); assert.doesNotMatch((await startReading(at(PLUGIN_API))).text, /older pluginApi/, "a plugin on the interface this Coherence runs"); }); @@ -338,17 +339,16 @@ test("a project's plugin reads the plugin interface of the Coherence that runs, // The project installed another copy of the package, whose registry no plugin filled: what a global install, a checkout or another workspace's copy runs beside. const root = project({ "coherence.config.json": JSON.stringify({ language: ["zz"], plugins: { zz: "./plugins/zz" } }), - "plugins/zz/plugin.json": JSON.stringify({ name: "zz", version: "0.1.0", pluginApi: 2, provides: { language: "zz" }, module: "./index.ts", extensions: [".zz"], syntax: { topLevel: "top.ts#zzDeclaresAtTop" } }), + "plugins/zz/plugin.json": JSON.stringify({ name: "zz", version: "0.1.0", pluginApi: 2, provides: { language: "zz" }, module: "./index.ts", extensions: [".zz"], syntax: { notice: "notice.ts#zzNotice" } }), "plugins/zz/index.ts": 'import { languageOfFile } from "@posthog/coherence/plugin";\nexport default { adapter: () => { throw new Error("not asked"); }, languageOf: (file) => languageOfFile(file) };\n', - "plugins/zz/top.ts": 'import { languageOfFile } from "@posthog/coherence/dist/plugins/api.js";\nexport const zzDeclaresAtTop = (text, name) => languageOfFile("app/accounts.zz") === "zz" && text.includes(name);\n', + "plugins/zz/notice.ts": 'import { languageOfFile } from "@posthog/coherence/dist/plugins/api.js";\nexport const zzNotice = () => (languageOfFile("app/accounts.zz") === "zz" ? "zz is read" : "");\n', "node_modules/@posthog/coherence/package.json": JSON.stringify({ name: "@posthog/coherence", version: "0.0.1", type: "module", exports: { "./plugin": "./dist/plugins/api.js", "./dist/*": "./dist/*" } }), "node_modules/@posthog/coherence/dist/plugins/api.js": 'export const languageOfFile = () => undefined;\nexport const copy = "the project\'s";\n', "tools/copy.ts": 'export { copy } from "@posthog/coherence/plugin";\n', }); const config = readEnforcementConfig(root); const plugin = config.plugins.find((p) => p.name === "zz")!; - const topLevel = syntaxOf("zz", "topLevel"); - assert.ok(typeof topLevel === "function" && topLevel("verb reset\n", "reset"), "a syntax slot, loaded by require, reads the registry that holds zz"); + assert.equal(syntaxOf("zz", "notice")?.(root), "zz is read", "a syntax slot, loaded by require, reads the registry that holds zz"); type Probe = { languageOf: (file: string) => string | undefined }; assert.equal((moduleSyncOf(plugin) as unknown as Probe).languageOf("app/accounts.zz"), "zz", "the module loaded by require reads it"); assert.equal(((await moduleOf(plugin)) as unknown as Probe).languageOf("app/accounts.zz"), "zz", "the module loaded by import reads it"); diff --git a/src/plugins/languages.ts b/src/plugins/languages.ts index d2375d27..49f6dafc 100644 --- a/src/plugins/languages.ts +++ b/src/plugins/languages.ts @@ -26,7 +26,11 @@ import { join, resolve } from "node:path"; import type { AdapterBounds, LanguageAdapter, Ladder } from "../adapters/adapter.ts"; import type { DeclaredLanguage } from "../adapters/declared-config.ts"; import type { BoundarySource } from "../scaffold/boundaries.ts"; -import type { CiStep, EntranceRule, LoadedPlugin, MarkedFolder, PluginManifest, PluginModule, SyntaxSlot, SyntaxTables } from "./plugin.ts"; +import { INTERFACE_FACTS, type CiStep, type EntranceRule, type LoadedPlugin, type MarkedFolder, type ModuleResolution, type PluginManifest, type PluginModule, type SyntaxSlot, type SyntaxTables } from "./plugin.ts"; +import type { InterfaceSymbol } from "../observation/interfaces.ts"; +import type { SourceSyntax } from "../economy/source.ts"; +import type { InterfaceReadings } from "../readings/scope/component-interfaces.ts"; +import { treeReaderOf, type TreeDeclaration, type TreeReader } from "./syntax-trees.ts"; import { BUNDLED_DIR, moduleSyncOf, readManifest, throughThisCore } from "./registry.ts"; import { setLanguageData } from "../readings/scope/language-data.ts"; @@ -350,8 +354,8 @@ export function languageDataTable(): Record = {}; for (const { language } of providers()) { const entrances = fieldOf(language, "entrances"); - // A plugin that fills no source slot reads no text of its language: said, never read as an empty project. - const reason = fieldOf(language, "notScanned") ?? (fillsSlot(language, "source") ? undefined : `the ${language} plugin fills no source slot, so no text scan reads ${language}'s declarations or imports`); + // A plugin that names no parser reads no text of its language: said, never read as an empty project. + const reason = fieldOf(language, "notScanned") ?? (sourceProvider(language)?.manifest.treeSitter !== undefined ? undefined : `the ${language} plugin names no treeSitter parser, so no text scan reads ${language}'s declarations or imports`); table[language] = { rules: [...entranceRules(language)], ...(entrances === undefined ? {} : { notDetected: entrances.notDetected }), ...(reason === undefined ? {} : { notScanned: reason }) }; } return table; @@ -374,10 +378,6 @@ export function moduleFolderOf(file: string): string | undefined { } /** Whether any plugin answering for the language fills the slot, read from the manifests alone: the swap, the provider, or a plugin that extends it. */ -export function fillsSlot(language: string, slot: SyntaxSlot): boolean { - const filled = (p: LoadedPlugin | undefined): boolean => p?.manifest.syntax?.[slot] !== undefined; - return filled(swapsNow().get(language)) || filled(baseProvider(language)) || extendersOf(language).some(filled); -} /** How the language's exported type bodies read, for the lexicon's member scan; undefined when its plugin says nothing. */ export function memberScanOf(language: string): { opens: RegExp; closes: RegExp; field: RegExp } | undefined { @@ -430,12 +430,15 @@ const slots = new Map(); /** * One syntax slot of a language, loaded from the module its plugin's * manifest names, synchronously and once; undefined when the plugin leaves - * the slot empty, which a reading reads as "not read for ". + * the slot empty, which a reading reads as "not read for ". No + * slot answers a reading of the language's declarations, imports or exports: + * those are parsedOf's, through its parser, and an interfaces table that + * answers one is refused (statedFacts). */ export function syntaxOf(language: string, slot: S): SyntaxTables[S] | undefined { // The swap's slot when it fills it, else the bundled provider's: a plugin that replaces only the adapter keeps the readings. const swap = swapsNow().get(language); - const plugin = swap?.manifest.syntax?.[slot] !== undefined ? swap : baseProvider(language); + const plugin = fills(swap, slot) ? swap : baseProvider(language); const provided = plugin === undefined ? undefined : (slotExport(plugin, slot) as SyntaxTables[S] | undefined); const extenders = extendersOf(language).filter((p) => p.manifest.syntax?.[slot] !== undefined); if (extenders.length === 0) return provided; @@ -444,27 +447,175 @@ export function syntaxOf(language: string, slot: S): Synta extenders.reduce((beneath, extender) => { const wrap = slotExport(extender, slot); if (typeof wrap !== "function") throw new Error(`plugin ${extender.name} extends ${language}, so its syntax.${slot} names a function of the table beneath it, not a table`); - return (wrap as (beneath: SyntaxTables[S] | undefined) => SyntaxTables[S])(beneath); + const wrapped = (wrap as (beneath: SyntaxTables[S] | undefined) => SyntaxTables[S])(beneath); + return slot === "interfaces" ? (statedFacts(extender, wrapped) as SyntaxTables[S]) : wrapped; }, provided), ); } -/** The export a plugin's manifest names for a slot, loaded synchronously and once; undefined when it leaves the slot empty. */ +/** Whether a plugin fills a slot: its manifest names an export for it. */ +function fills(plugin: LoadedPlugin | undefined, slot: SyntaxSlot): boolean { + return plugin?.manifest.syntax?.[slot] !== undefined; +} + +/** What the core reads of a language's declarations, imports and exports, each derived from one parse through the parser its plugin names (parsedOf), never filled by a plugin. */ +export interface ParsedReadings { + /** The economy's and mass's scan: the names a line declares, the imports a text holds, and where an import leads (the plugin's treeSitter.resolve). */ + source: SourceSyntax; + /** What a declaration line's keyword says can execute, for the observation's interface reading. */ + declares: (line: string) => InterfaceSymbol["declares"]; + /** Whether a file's text declares a name at its top level, for the spec model's check that a handler, guard or mirror exists. */ + topLevel: (text: string, name: string) => boolean; + /** The component interface reading's and the kept answers' reading of a file: its type declarations, default exports, import lists and wildcard imports. */ + interfaces: InterfaceReadings; +} +export type ParsedReading = keyof ParsedReadings; + +/** + * A reading of a language's text, derived from one parse through the parser + * its source provider names (syntax-trees.ts); undefined for a language whose + * plugin names none, which the readings say is not read. The one way the + * core reads a language's declarations, imports and exports: no plugin slot + * answers one (DERIVED_SLOTS, INTERFACE_FACTS). The entrances and lists slots + * still read a file's text, for what no parse here derives. + */ +export function parsedOf(language: string, reading: R): ParsedReadings[R] | undefined { + const plugin = sourceProvider(language); + return plugin?.manifest.treeSitter === undefined ? undefined : (treeSlot(plugin, reading) as ParsedReadings[R]); +} + +/** The export a plugin's manifest names for a slot, loaded synchronously and once; undefined when it leaves the slot empty. An interfaces table is held to its facts (statedFacts); an extending plugin's, a function of the table beneath, is held where it is called. */ function slotExport(plugin: LoadedPlugin, slot: SyntaxSlot): unknown { const at = plugin.manifest.syntax?.[slot]; if (at === undefined) return undefined; + const value = exportAt(plugin, at, `syntax.${slot}`); + return slot === "interfaces" && typeof value !== "function" ? statedFacts(plugin, value) : value; +} + +/** + * An interfaces table, refused by name when it answers anything but its + * language's facts (INTERFACE_FACTS): a member that reads the language's + * text (importLists, wildcardModules, isTypeDeclaration, isDefaultExport, + * defaultNames, as pluginApi 3's tables did) would be a second reader of what + * the parse reads, whether or not the plugin names a parser. The core reads + * those through parsedOf alone, so such a member could never be read; it is + * refused rather than ignored, so a plugin's author learns it went unread. + */ +function statedFacts(plugin: LoadedPlugin, table: unknown): unknown { + if (table === undefined || table === null || typeof table !== "object") return table; + const readers = Object.keys(table).filter((member) => !(INTERFACE_FACTS as readonly string[]).includes(member)); + if (readers.length > 0) throw new Error(interfaceReadersRefused(plugin.name, readers)); + return table; +} + +/** The refusal of an interfaces table's readers, naming each and what to do. */ +export function interfaceReadersRefused(plugin: string, readers: readonly string[]): string { + const named = readers.length === 1 ? readers[0]! : `${readers.slice(0, -1).join(", ")} and ${readers[readers.length - 1]!}`; + return `plugin ${plugin}'s interfaces table answers ${named}, which this Coherence does not read (pluginApi 4): the table states only ${INTERFACE_FACTS.join(", ")}, and a language's type declarations, default exports, import lists and wildcard imports are read through its treeSitter parser alone (docs/plugins.md, Reading through a parser); remove ${readers.length === 1 ? "it" : "them"}, or, for a copy ejected from an older Coherence, eject it again from this one (coherence plugin eject ) and reapply your changes`; +} + +/** The export "#" of a plugin's, loaded synchronously and once. */ +function exportAt(plugin: LoadedPlugin, at: string, field: string): unknown { const key = `${plugin.dir}\u0000${at}`; if (!slots.has(key)) { const [file, name] = at.split("#") as [string, string]; throughThisCore(plugin); const module = load(resolve(plugin.dir, file)) as Record; // Its own export only: a name the module inherits (constructor, toString) is no slot. - if (!Object.hasOwn(module, name)) throw new Error(`plugin ${plugin.name}'s syntax.${slot} names ${at}, whose module exports no ${name}`); + if (!Object.hasOwn(module, name)) throw new Error(`plugin ${plugin.name}'s ${field} names ${at}, whose module exports no ${name}`); slots.set(key, module[name]); } return slots.get(key); } +/** The plugin a language's text is read through: the project's swap when it names a parser, else the provider beneath it, which may name none. */ +export function sourceProvider(language: string): LoadedPlugin | undefined { + const swap = swapsNow().get(language); + return swap?.manifest.treeSitter !== undefined ? swap : baseProvider(language); +} + +/** The reader of a language's text through its parser: the source provider's, when it names one; undefined otherwise. */ +export function treeReaderFor(language: string): TreeReader | undefined { + const plugin = sourceProvider(language); + return plugin === undefined ? undefined : treeReaderOf(plugin, rootNow()); +} + +/** + * A reading the core derives for a plugin on the parser path, built once: + * every one reads the text through the same parse (syntax-trees.ts), and + * where an import leads through the plugin's resolve. + */ +function treeSlot(plugin: LoadedPlugin, slot: ParsedReading): unknown { + const key = `${plugin.dir}\u0000tree\u0000${slot}`; + if (slots.has(key)) return slots.get(key); + // The project asking, at each call: the table is built once, and a project's files are kept parses, a line alone is not. + const reader = (): TreeReader => treeReaderOf(plugin, rootNow())!; + // A question about one line (what it declares) parses the line alone: no project's store keeps it, since no file is that line. + // A line that opens a bracket it does not close (export default function Page({) is read again with them closed, as its statement goes on. + const lineDeclaration = (line: string): TreeDeclaration | undefined => { + const reader = treeReaderOf(plugin)!; + const declared = reader.declarations(line)[0]; + if (declared !== undefined) return declared; + const closers = unclosed(line); + return closers === "" ? undefined : reader.declarations(line + closers)[0]; + }; + const resolution = (): ModuleResolution => { + const value = exportAt(plugin, plugin.manifest.treeSitter!.resolve, "treeSitter.resolve") as ModuleResolution; + if (typeof value?.resolveModule !== "function" || typeof value.modulePaths !== "function") throw new Error(`plugin ${plugin.name}'s treeSitter.resolve names ${plugin.manifest.treeSitter!.resolve}, which is no { resolveModule, modulePaths }`); + return value; + }; + const boundName = (specifier: string): string => resolution().boundName?.(specifier) ?? specifier.split("/").pop() ?? specifier; + let table: unknown; + if (slot === "source") { + table = { + resolveModule: (root: string, from: string, specifier: string, vanished: ReadonlySet) => resolution().resolveModule(root, from, specifier, vanished), + // A glob brings in no name of its own: the kept answers and the word index read it, through wildcardModules. + // A whole module whose names the text uses through the name the import binds (st.Seal, where the queries capture uses) brings in those names, each joined to the module's file that declares it; one the text uses no name of stays whole. + importsOf: (text: string, add: (name: string | undefined, specifier: string) => void) => { + const uses = reader().uses(text); + for (const imported of reader().imports(text)) { + if (imported.glob === true) continue; + const used = imported.name === undefined && uses.size > 0 ? uses.get(imported.alias ?? boundName(imported.specifier)) : undefined; + if (used === undefined) add(imported.name, imported.specifier); + else for (const name of [...used].sort()) add(name, imported.specifier); + } + }, + } satisfies SourceSyntax; + } else if (slot === "declares") table = (line: string) => lineDeclaration(line)?.declares ?? "unknown"; + else if (slot === "topLevel") table = (text: string, name: string) => reader().topLevel(text).has(name); + else if (slot === "interfaces") { + table = { + isTypeDeclaration: (line: string) => lineDeclaration(line)?.declares === "type", + // A module's default export, where the queries capture it (@default): the declaration that is it, and the names exported as it. + isDefaultExport: (line: string) => lineDeclaration(line)?.isDefault === true, + defaultNames: (text: string) => reader().defaults(text), + importLists: (text: string) => { + const renamed = reader().imports(text).filter((i) => i.alias !== undefined); + return renamed.length === 0 ? [] : [renamed.map((i) => `${i.name ?? i.specifier} as ${i.alias}`).join(", ")]; + }, + wildcardModules: (file: string, text: string) => reader().imports(text).filter((i) => i.glob === true).flatMap((i) => resolution().modulePaths(file, i.specifier)), + } satisfies InterfaceReadings; + } + slots.set(key, table); + return table; +} + +/** The closers of every bracket a line opens and leaves open, innermost first; brackets inside a quoted string are none. */ +function unclosed(line: string): string { + const open: string[] = []; + let quote: string | undefined; + for (let i = 0; i < line.length; i++) { + const c = line[i]!; + if (quote !== undefined) { + if (c === "\\") i++; + else if (c === quote) quote = undefined; + } else if (c === '"' || c === "'" || c === "`") quote = c; + else if (c === "(" || c === "[" || c === "{") open.push(c === "(" ? ")" : c === "[" ? "]" : "}"); + else if ((c === ")" || c === "]" || c === "}") && open[open.length - 1] === c) open.pop(); + } + return open.reverse().join(""); +} + /** * The answers a plugin gives twice: each pair of its slots' functions (a slot * that is a function, or a function of a slot's table) that are one function, @@ -499,7 +650,7 @@ export function repeatedAnswers(plugin: LoadedPlugin): string[] { /** Every module the core's language plugins answer from, by absolute path: their adapter modules and the modules their syntax slots name. */ export function languageCode(): string[] { return [...providers().map(({ plugin }) => plugin), ...[...swapsNow().keys()].flatMap((l) => bundledProvider(l) ?? [])].flatMap((plugin) => { - const files = [plugin.manifest.module, ...Object.values(plugin.manifest.syntax ?? {}).map((at) => at.split("#")[0])].filter((f): f is string => f !== undefined); + const files = [plugin.manifest.module, ...[...Object.values(plugin.manifest.syntax ?? {}), plugin.manifest.treeSitter?.resolve].map((at) => at?.split("#")[0])].filter((f): f is string => f !== undefined); return [...new Set(files)].map((f) => resolve(plugin.dir, f)); }); } diff --git a/src/plugins/plugin-coherence.test.ts b/src/plugins/plugin-coherence.test.ts index a8667511..b454ee5d 100644 --- a/src/plugins/plugin-coherence.test.ts +++ b/src/plugins/plugin-coherence.test.ts @@ -1,8 +1,9 @@ /** - * The plugin interface kept to one model of each language: a slot a plugin - * leaves empty is said as not read, never read as an empty project; no - * plugin answers one question in two slots; and the core names no - * language's files, which are its plugin's to name. + * The plugin interface kept to one model of each language: a language whose + * plugin names no parser, or a slot a plugin leaves empty, is said as not + * read, never read as an empty project; no plugin answers one question in + * two slots; and the core names no language's files, which are its + * plugin's to name. */ import assert from "node:assert/strict"; @@ -36,19 +37,18 @@ function project(files: Record): string { const STAND_IN = 'export default { adapter: ({ language }) => ({ language, ladder: { top: "reference-choked", because: "a stand-in", rungs: [] }, ready: async () => ({ ok: true }), resolve: async () => ({ ok: false, reason: "a stand-in" }), references: async () => [], visibility: async () => ({ enforced: false, visible: true, evidence: "a stand-in" }), testFilter: (via) => via, refute: async () => ({ seen: false, staged: [], account: "a stand-in" }), forget: async () => {}, close: async () => {} }) };\n'; -test("a plugin that fills no source slot is named not read by mass, with why, never measured as a project of no code", () => { +test("a plugin that names no parser is named not read by mass, with why, never measured as a project of no code", () => { const root = project({ "coherence.config.json": JSON.stringify({ language: ["zz"], plugins: { zz: "./plugins/zz" } }), - "plugins/zz/plugin.json": JSON.stringify({ name: "zz", version: "0.1.0", pluginApi: 2, provides: { language: "zz" }, module: "./index.ts", extensions: [".zz"], syntax: { topLevel: "top.ts#zzDeclaresAtTop" } }), + "plugins/zz/plugin.json": JSON.stringify({ name: "zz", version: "0.1.0", pluginApi: 2, provides: { language: "zz" }, module: "./index.ts", extensions: [".zz"] }), "plugins/zz/index.ts": STAND_IN, - "plugins/zz/top.ts": "export const zzDeclaresAtTop = (text, name) => text.split(\"\\n\").includes(`verb ${name}`);\n", "app/accounts.zz": "verb reset\nverb rename\n", }); readEnforcementConfig(root); const report = computeMass(root); assert.deepEqual(report.languages.read, []); assert.deepEqual(report.languages.unread.map((u) => u.language), ["zz"]); - assert.match(report.languages.unread[0]!.because, /the zz plugin fills no source slot/); + assert.match(report.languages.unread[0]!.because, /the zz plugin names no treeSitter parser/); assert.match(formatMass(report), /zz NOT READ/); }); diff --git a/src/plugins/plugin-docs.test.ts b/src/plugins/plugin-docs.test.ts new file mode 100644 index 00000000..e4acae8a --- /dev/null +++ b/src/plugins/plugin-docs.test.ts @@ -0,0 +1,124 @@ +/** + * docs/plugins.md held to the code it describes: its tables list exactly + * what the code holds, its examples validate as what they show, and its + * claims about the bundled plugins are true of them. A plugin author follows + * the guide, and the guide steered authors to hand-written readers after + * Python moved to a parser (mnemion's Swift plugin, written from the + * 1.11.0-beta.0 docs), which pluginApi 4 then removed, so the guide is + * checked as code is. + */ + +import assert from "node:assert/strict"; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join, resolve } from "node:path"; +import { after, test } from "node:test"; +import { LANGUAGE_DUTIES } from "./check.ts"; +import { parsedOf, syntaxOf } from "./languages.ts"; +import { ADAPTER_METHODS, INTERFACE_FACTS, MANIFEST_KEYS, PLUGIN_API, SYNTAX_SLOTS, TREE_SITTER_KEYS, type PluginManifest } from "./plugin.ts"; +import { BUNDLED_DIR, readManifest } from "./registry.ts"; +import { CAPTURES } from "./syntax-trees.ts"; + +const DOC = readFileSync(resolve("docs/plugins.md"), "utf8"); +const fixtures: string[] = []; +after(() => { + for (const dir of fixtures) rmSync(dir, { recursive: true, force: true }); +}); + +/** The first cells of the table whose header row begins with `header`, each cell's names: its backticked ones, or the cell's text when it has none. */ +function tableNames(header: string): string[] { + const lines = DOC.split("\n"); + const start = lines.findIndex((l) => l.trim().startsWith(`| ${header} |`)); + assert.ok(start >= 0, `docs/plugins.md has a table headed ${header}`); + const names: string[] = []; + for (const line of lines.slice(start + 2)) { + const row = line.trim(); + if (!row.startsWith("|")) break; + const cell = row.split("|")[1]!.trim(); + const ticked = [...cell.matchAll(/`([^`]+)`/g)].map((m) => m[1]!.replace(/\(.*\)$/, "")); + names.push(...(ticked.length > 0 ? ticked : [cell])); + } + return names; +} + +const sorted = (values: Iterable): string[] => [...new Set(values)].sort(); + +test("docs/plugins.md's tables list exactly what the code holds: the duties plugin check runs, the manifest's keys, the syntax slots, the treeSitter keys, the captures and the adapter's methods", () => { + assert.deepEqual(sorted(tableNames("Duty")), sorted(LANGUAGE_DUTIES), "the duty table"); + assert.deepEqual(sorted(tableNames("Key")), sorted(MANIFEST_KEYS), "the manifest key table, the first headed Key"); + assert.deepEqual(sorted(tableNames("Slot")), sorted(SYNTAX_SLOTS), "the syntax slot table"); + // The second Key table is treeSitter's. + const second = DOC.split("\n").findIndex((l, i, all) => l.trim().startsWith("| Key |") && all.slice(0, i).some((m) => m.trim().startsWith("| Key |"))); + const treeKeys: string[] = []; + for (const line of DOC.split("\n").slice(second + 2)) { + if (!line.trim().startsWith("|")) break; + treeKeys.push(...[...line.split("|")[1]!.matchAll(/`([^`]+)`/g)].map((m) => m[1]!)); + } + assert.deepEqual(sorted(treeKeys), sorted(TREE_SITTER_KEYS), "the treeSitter key table"); + assert.deepEqual(sorted(tableNames("Capture").map((c) => c.replace(/^@/, ""))), sorted(CAPTURES), "the capture table"); + assert.deepEqual(sorted(tableNames("Method")), sorted(ADAPTER_METHODS), "the adapter method table"); +}); + +test("every plugin.json example in docs/plugins.md validates as a manifest of the interface version this Coherence runs, and every treeSitter example names only treeSitter's keys", () => { + const blocks = [...DOC.matchAll(/```json\n([\s\S]*?)```/g)].map((m) => m[1]!); + const manifests = blocks.filter((b) => b.includes('"pluginApi"')); + assert.ok(manifests.length > 0, "the guide shows a manifest"); + for (const text of manifests) { + const manifest = JSON.parse(text) as PluginManifest; + assert.equal(manifest.pluginApi, PLUGIN_API, `the example is written for pluginApi ${manifest.pluginApi}, and this Coherence runs ${PLUGIN_API}`); + // Beside it, a file at every path it names, so the manifest is held to its shape and not to files the page cannot ship. + const dir = mkdtempSync(join(tmpdir(), "coherence-doc-manifest-")); + fixtures.push(dir); + const named = [manifest.module, manifest.lexicon, manifest.treeSitter?.parser, manifest.treeSitter?.queries].filter((p): p is string => p !== undefined); + for (const path of named) { + mkdirSync(dirname(join(dir, path)), { recursive: true }); + writeFileSync(join(dir, path), ""); + } + writeFileSync(join(dir, "plugin.json"), text); + assert.deepEqual(readManifest(manifest.name, dir, "docs/plugins.md").problems, [], "the example validates"); + } + for (const text of blocks.filter((b) => b.trim().startsWith('"treeSitter"'))) { + const fragment = JSON.parse(`{${text}}`) as { treeSitter: Record }; + for (const key of Object.keys(fragment.treeSitter)) assert.ok((TREE_SITTER_KEYS as readonly string[]).includes(key), `treeSitter example names ${key}`); + } +}); + +test("docs/plugins.md's claims about the bundled plugins are true of them: each named as read through a parser names one, and the plugin it says to start from reads through a parser", () => { + const manifest = (name: string): PluginManifest => readManifest(name, join(BUNDLED_DIR, name), "docs/plugins.md").manifest!; + const claims = [...DOC.matchAll(/