Repository navigation
Read every bundled language through a tree-sitter parser; keep parses as files of their own; release 1.11.0 - #157
Merged
Merged
Conversation
- Entrances: each pub method and constructor of a #[wasm_bindgen] impl, #[wasm_bindgen(start)], #[uniffi::export] fns and an exported impl's methods (a trait impl's all) are foreign exports, named Type::method; an extern block's imports, private, pub(crate), skipped and plain impls' methods are not. An example's main at Cargo's default paths is a new example rule. - Lists: rustListOf fills the lists slot (a top-level const or static array: strings, tuples by their first, paths by their last segment), and mirrors.ts now reads a list through its language's lists slot, which no core module read before. - Manifest: testFiles ^tests\.rs$; pkg beside Cargo.toml is wasm-pack output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CodeQL's js/unvalidated-dynamic-method-call: the reader comes from a plugin's syntax slot, chosen by the list file's language. A slot that is not a function now falls back to the TypeScript reader instead of throwing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…from one parse A plugin's manifest may name a tree-sitter parser and queries (treeSitter); the core derives its source, declares and topLevel slots and its interfaces table's import answers from the parse (src/plugins/syntax-trees.ts), and refuses a hand-written reader of the same text beside it. The parser runtime (web-tree-sitter 0.27.1, the package's first runtime dependency) starts once per process, in the CLI and the test preload; every tree is freed. Each file's parse is kept in .coherence/parses by content digest, and the warm-up a session start launches pre-reads the project, so a whole-project reading parses only what changed (PostHog mass 3.4 s; 14.8 s unkept). Python moves first: python.scm and the parser from tree-sitter-python 0.25.0 replace its three hand-written readers, which disagreed about a from-import split across lines (df-7ac38ee4). Five invariants in src/plugins/Plugins.spec.md, each refuted and witnessed. Experiment x-adaa7243. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A plugin's resolveModule may return a module, its folder and every file of it, where the language's module is several files (a Go package, a SwiftPM target). The core joins each imported name to the module's files that declare it, and every file when the module is imported whole or no file declares the name (src/economy/source.ts importsOf), so no plugin picks a file of a module by a rule of its own. Four plugins had four such rules, and every one missed a file its importer used (d-cb7829df, c-38a1baae). Go drops its path#Name specifiers: its imports now carry the names they use, and its packages resolve as modules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
parse-gap held defects in entrance rules, Python URL patterns, the shell reader and Python's imports, which no one guard covers, so the first guard any of them got stood for all and made df-7ac38ee4 read as its failure. It is now a family (d-1ad22dfb), and df-53e501ca, misfiled there, is classed silent-skip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new duty, answers agree, runs over every file of each check project the slots that answer one question of the same text: a name the source scan declares is one topLevel finds at the top level; a type declaration where interfaces and declares both say so; a name an interfaces import list renames is one the source scan reads imported. An unknown kind is no answer. Over a check project whose renamed import spans lines, Python's two hand-written readers from before its parser fail it, naming the name (df-7ac38ee4). Every bundled language plugin passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…beta.0 coherence plugin shapes counts every shape of import a project writes through its parser beside the plugin's check projects, naming each no check project holds. plugin check gains server agrees (every declaration the text reading finds is a top-level symbol the language server reports, through a new optional adapter method, topLevelSymbols) and reference reading (every language plugin's check project maps one reference project, a two-file store, a render using both, a main, and its readings must recover each relation); coherence plugin calibrate and coherence plugin compare are the readings of the same over a real project and across every plugin. Python's check project now holds every import shape; every bundled check project holds the reference project. Found on the way: Python's own plugin check was failing on this branch (df-11317061, now guarded); three vias named no test exactly (df-03839b92); a star-import reference Pyright reports only sometimes (df-e2663a97). A prerelease version publishes under its own dist-tag and is a GitHub prerelease (release.yml). Version 1.11.0-beta.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parse store refuses a link anywhere on its path, reads and appends through no link, creates its temporary file exclusively, removes only its own files, reads only files signed with a machine key, and runs one warm-up at a time (df-7c50adfe: a repository committing .coherence/parses/python as a link to ~/.ssh had the warm-up empty it; shipped in v1.11.0-beta.0, now deleted). It flushes in batches, and one-line parses keep out of it. A whole-module import reaches a reference name only where the importer spells it; Rust's reference entry is its real main.rs. Plugin interface 3 brings the parser path, module imports, topLevelSymbols and the reference map; a plugin written for 2 is told those duties are not held, never failed. An extending plugin's source wrapper is honoured over a parser. plugin shapes reads the check projects plugin check reads, by language, counting only imports that resolve there. TypeScript reads re-exports as imports. The release tag is the prerelease's leading letters, or next. Nits: parser paths stay in the plugin folder, the fingerprint names the runtime, nested symbols leave a flat server answer, the declared-names stamp is to the nanosecond, Go reports every name a line declares. The docs point new-language authors at the parser path and Python, not Go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…laims docs/plugins.md's duty, manifest key, syntax slot, treeSitter key, capture and adapter method tables are held to the lists the code holds; the manifest, treeSitter and adapter lists are pinned to their types, so a member added to a type fails the typecheck until the list, and the guide, name it. Every plugin.json example validates at the interface version this Coherence runs. The guide marks which bundled plugins read through a parser and which by hand, and says which to start from; each mark is held to the manifests. Holding them found the manifest table missing basisFiles and moduleFolders, naming provides.language for provides, and the capture table missing @import; each is fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 grew a log nothing folded in (df-266d6a61). Parses are now kept at the registry's top (storeRootOf), a leaf's warm-up pre-reads the top's files too, and the rewrite prunes by age, keeping anything seen in the last 14 days, so one leaf's pass keeps the others'. Mass at the top after a warm-up: 3.6 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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. It is now a family: each cost defect closes with its own guard or a decision. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Go plugin names a treeSitter block (tree-sitter-go 0.25.0's wasm,
go.scm, GO_RESOLVE, privateName ^\P{Lu}); its hand-written source,
declares, topLevel and interfaces readers are gone, and its entrances
read their own funcs and router imports. The core pairs a name used
through a qualifier (@use.qualifier, @use.name: st.Seal) with the
whole-module import that binds it (its alias, else the resolution's
boundName, else the specifier's last path element), so a Go import
still joins only the package file declaring the name it uses.
privateName is read with Unicode classes. The check project renames
one import, so plugin shapes finds the renamed shape held.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om one parse
Rust joins Python on the parser path: plugins/rust names tree-sitter-rust
0.24.0's wasm and rust.scm (treeSitter), and the hand-written source,
declares and topLevel slots (RUST_SOURCE, rust-interfaces.ts,
rust-top-level.ts) and the interfaces table's import answers are gone.
Where an import leads stays code: RUST_RESOLVE in rust-source.ts.
Core: a query may capture @import.prefix, a path a group of imports
shares; the core joins every prefix over an import's specifier, outer
first, with the manifest's treeSitter.separator, so use a::{b::{c as d}}
reads a::b::c at any depth. The census places an import whose match
captures no statement in the statement a match of its own captures.
An inline mod's keyword prefixes the paths inside it, so use super::* in
a test module is read from that module: over PostHog's rust/, 692 imports
the line reader resolved one module too high are gone, 17 it missed are
read; declarations agree on all 15,683.
Rust's check project gains a renamed, globbed, multi-line and in-block
import. Four invariants restated or new, each refuted and witnessed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ading derived from one parse The TypeScript plugin names a treeSitter parser: tree-sitter-tsx.wasm from tree-sitter-typescript 0.23.2 reads every file of its pattern (the TSX grammar reads each .ts file of PostHog's and Coherence's the TypeScript grammar reads, but one vendored <any>row cast; the TypeScript grammar errs on 3,196 of PostHog's 3,510 .tsx files), with typescript.scm. Its hand-written source, declares and topLevel readers and its interfaces table's import and default answers are gone; resolution stays code (TYPESCRIPT_RESOLVE). Core, additive: @import.default (a default import, read as the name default) and @default (the default export, declared or by name) captures; a capture whose name starts with an underscore is the queries' own, for a predicate; a declaration whose value the queries know wins over an unknown match of the same name and line; a line that leaves brackets open is read again with them closed; declarations carry isDefault, which the interface reading reads. plugin eject copies a file that is no module byte for byte, so an ejected parser plugin's .wasm is no longer corrupt. Corpus comparison against beta-fixes' readers over Coherence (352 files) and PostHog (15,507 files): every difference classed; the new reader is wrong only past a grammar error (27 PostHog files) and for 10 local export renames (d-b4fe6dee). The check project gains a barrel putting renamed, glob, whole module and multi-line imports to the plugin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#156 # Conflicts: # src/plugins/Plugins.spec.md # src/plugins/registry.ts # src/plugins/syntax-trees.test.ts # src/plugins/syntax-trees.ts
…sitter Every bundled language plugin now reads through a parser. The merge keeps Go's qualified uses and Rust's prefixes beside TypeScript's default exports and the queries' own underscore captures. The guide says so: the claims marker names all four as parser-read, the capture and treeSitter tables gain @import.prefix, @import.default, @default, @use.qualifier, @use.name, separator and boundName, and it names what each grammar cannot read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Making cost a family (b78ee04) meant a later cost defect is no guard failure, so the convergence test, which counted a repeat in cost, read none. The test now repeats in overmatch, a declared class that keeps the guard rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…audits them The parse store's fingerprint digested the parser and the queries alone, while Rust's separator shapes the specifier a kept parse holds, and an edit to how a tree is read kept its fingerprint (df-b9b2d3ef). Now: - fingerprintOf 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, plus the store format, the web-tree-sitter release and syntax-trees.ts's own source; - a test holds each left-out key (privateName, resolve) to change no kept parse of any bundled plugin's check project, and syntax-trees.ts to import no other Coherence code that could shape a parse at run time; - each warm-up re-parses a sample of eight kept texts; any difference discards the store whole, and orient says so for a week. Also restores the Go bullet's kinds line, which the Rust merge dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- An old-style cast (<any>x) in a .ts file no longer hides every later declaration (df-42f25182). treeSitter gains an optional alternate parser, read with the same queries where the parser's tree errs and its own errs less; TypeScript names the TypeScript grammar beside TSX. Its queries name no JSX node so both compile: a JSX constant declares unknown. The guide no longer claims statements around a grammar error still read. - The parse store signs its contents, not only its fingerprint, and each log line signs itself (df-aad5bf07). The forged-store test wrote a malformed body the shape check refused first, so it never tested the seal; its forgery is now well formed. - A folder committed where the store's file goes, or a lock stamped in the future, no longer stops a warm-up; the stale-parses audit is signed and bounded, so a committed audit.json says nothing at a session start. - A long-lived process reloads a store another process rewrote; the fingerprint digests the very bytes compiled; the import guard catches re-exports and dynamic imports; the guide's claims refutation is witnessed again against a break that still fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
beta.1 was cut from a branch that never took #153, so it put "use these names" and the over-cap vocabulary back in adopters' session starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream has merged no grammar change since 0.23.2 (2024-11), and its
grammars left an error in 64 of PostHog's 5,832 frontend files, hiding 44
declarations in three of them (df-fead3a57). Both parsers are now built
from 0.23.2 with grammars/tree-sitter-typescript/coherence.patch:
- an import type is a primary type and takes type arguments, so
import('x').T<U>, import('x').T[], keyof import('x').T and
import('x').T<U>['k'] parse (upstream #322);
- the semicolon scanner reads identifier characters after in and
instanceof, so a member named in_progress or in on the line after
another no longer reads as the operator;
- a bare & is JSX text and a JSX string's text (Billing & Usage,
to="?a=1&b=2"), and a character reference still reads as one.
Over PostHog's frontend one file still errs (an optional destructured
parameter in a function type, no declaration lost), the 44 are read, and
none is lost elsewhere. build.sh rebuilds both parsers byte for byte with
tree-sitter-cli 0.27.1 and Emscripten 6.0.13 (d-fd4e2e86).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Parse store (df-04fddaf1, df-8b32c22b): - A log a repository commits costs a few signatures, not one per line: a line is checked only where its signature has a signature's length, 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 MB log took 4.4 s; now 4 ms. - A folder or link at warming.lock no longer turns the warm-up off. - A process's own append no longer hides another's discard. - A pipe at the log's path no longer hangs a process. - An empty key file is replaced, and the key is linked into place whole. - Each claim is now held by a test: a forged log line, the alternate fingerprinted as a file of its own, and the cases above. - Test files get their own XDG_CONFIG_HOME, so the suite never writes the developer's key. Alternate parser (df-f1d6f9ce): chosen by the bytes its errors cover, not by how many there are, so a file mid-edit with a cast and two typos reads whole; compiled the first time a tree errs, not in every process. TypeScript grammar patch (df-7f3e3885): a name ends at Unicode white space, so `a\n in<NBSP>b` parses again as it did stock; a member named instanceof, `in?:` and a class field `in = 2` end the line before them; a bare & before a JSX string's quote leaves the quote. build.sh checks emcc 6.0.13 and fails unless both parsers match the recorded digests. Over 17,106 PostHog files: 191 erring files become 52, 85 declarations come back, none lost, none newly erring. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rence - The parse store touches its files only through StoreFolder, which refuses a link, a pipe, a folder or an oversized file and reads a log a chunk at a time. parsesFolder, the one place the store's path is made, is a chokepoint the compiler refuses outside the module (visibility-choked), and a totality oracle, reading syntax-trees.ts through the TypeScript plugin's own parser, fails on any node:fs use in store code outside the gateway. - A store's generation, in its signed first line, is made only by rewrite; each log line names the generation it was appended under; a process reads again when the generation on disk is not the one it loaded. No append can hide another process's rewrite or discard. A parse-based test holds newGeneration to ParseStore.rewrite. - The TypeScript parsers are pinned to the digests build.sh records, and build.sh builds only after tree-sitter-typescript's corpus and Coherence's own (each fix and each form it must leave alone, with its whole tree) pass in both dialects. CI's typescript-parsers job rebuilds them byte for byte in emsdk 6.0.13 on every pull request. The corpus fails e8f802e's patch and the over-eager scanner; TypeScript's own declaration files and node_modules' scripts failed neither. - src/lifecycle/prerelease.ts is the one way to cut a branch prerelease: it refuses unless the version is a prerelease, every bundled plugin and mod that follows the package names it, the tree is clean, HEAD is pushed, origin/main is an ancestor of HEAD and the tag is free. Each bullet refuted and witnessed batched and alone (d-78b9fc37). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each held defects in unrelated places 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. Each defect of either now closes with its own guard or a decision (d-2b2898cf). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bench/interfaces/own-tree.ts asked TypeScript's declarations of a runtime it never started and failed on PR #157's bench job; every bench script that reads Coherence's source in-process now starts it first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A file nested thousands deep around an error no longer crashes the warm-up and mass: errorSpan walks the tree with its own stack, the warm-up reads each text on its own, and treeOf frees both trees on every path (df-6e6c2b80). - The parse store: a long-lived reader reloads when the store's first line changes, so a store it cannot verify is read once; a log line is joined once, never copied per chunk; a discard seals an empty store under a new generation, so a reader of a log-only store sees it (df-1ebcefa2, df-2456bd98). A dead warm-up lock is removed only under a takeover lock one warm-up holds, and one no warm-up can read is taken over (df-ed777a88); files are created whole by link; an append refuses a file with a second name; a session start reads an audit only up to 4 KB. - The warm-up reads only a project's regular source files, never through a link or a pipe, none over 16 MB (df-194f5620). A relative XDG_CONFIG_HOME is ignored, as the XDG spec says. - The gateway and generation tests now catch createRequire, a built-in asked for by name, the store's folder spelled in a path, and an alias of ParseStore's folder; the store's link, O_NOFOLLOW and hard-link defenses are each held by a test (df-69c8ab4d, df-ff68d46c). - The TSX grammar's bare & in a JSX string is a pattern of its own, so the & operator is an & node again (df-7cc06057). The corpus pins members named in$, in2, inü and ina and character references at their limits. - build.sh fetches tree-sitter-cli 0.27.1, wasi-sdk 34 and binaryen 132 by digest and hands the compiler to the CLI, which downloaded it unchecked; the emcc check compiled nothing. It installs the parsers only once they match. CI's typescript-parsers job drops the emsdk container and verify waits on it (df-bf1275c5). - prerelease.ts releases to the repository package.json names, through its remote, fetched with --prune and read by full refs; it refuses untracked files, a manifest a major bump left behind, unknown arguments and a missing notes file (df-089ac5a9). - The plugin guide names what the patched grammar newly errs on, as tsc does, and where it recovers less (df-467db56c, d-6b0fbea9). - The Scope bench holds the page under 5 MB (d-08e78ac9). Each fix leaves its bug unrepresentable where the code allows it (d-262d3cd3), held by a test that reads the code: every store file is opened by StoreFolder's #openFile alone and each file system effect has one method; no function of syntax-trees.ts calls itself; only seal makes a generation, only get and seal set what a process loaded, only takeOver and unlock remove the warm-up lock; every TypeScript operator is a node of its own spelling; verify needs every CI job but the bench; every enumeration of the project passes isFileOnDisk, a regular file or a link to one; the prerelease script names no remote of its own. The kernel practice close a defect now teaches it to every project that runs Coherence: name what let the bug be written, fix it so the code cannot express it again, guard that against any second way to write it (d-b12df633, d-354e6716). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…th resolved ones; add a dead-end alarm Four rounds of blind review found about thirty defects in the parse store, each round's local fixes adding surface the next broke: the store shared the untrusted repository's namespace and was mutable shared state. This round changes the representation instead (d-d1229127). - Kept parses live in the user's cache ($XDG_CACHE_HOME/coherence/parses, else ~/.cache), filed by the parser's fingerprint and the text's digest, never in a project. A parse is written once, in a segment file written whole and never changed; a long-lived reader reads the segments others wrote since and reads again when one it read is gone; a warm-up merges more than eight segments, keeping what was read in fourteen days; one warm-up per project. The store is used only where the cache folder is the user's alone. Signing, generations, the log, the takeover lock, StoreFolder's hostile-folder defences and the code-reading tests that tried to rule out second doors are gone; every project, worktree and registry leaf shares one store. syntax-trees.ts: 1,206 lines at 887abd8 to 925. Two bullets retired by decision (d-ab934293, d-8aa2df3f). - The patched TypeScript grammar is held by its output, not by text: a stock-against-patched comparison over upstream's corpus, Coherence's, TypeScript's lib files and this repository's source, every node and every token by spelling, against intended-differences.json; it fails on all six rename variants a reviewer built. build.sh fetches and checks every input, then builds with no network (docker --network none in CI, sandbox-exec on macOS); both parsers rebuild byte for byte. - Prereleases are cut by .github/workflows/prerelease.yml from a clean checkout of a pushed branch, targeting its resolved sha, never npm; prerelease.ts only checks. - The dead-end alarm: spec --check, orient and the convergence reading name a component collecting defects across classes and rounds after its first guard, and print the escalation that asks a human whether to redesign; on this journal it names src/plugins alone. The journal is read from every worktree; a defect names its component. close a defect weighs a different design first where the alarm names the component. - The kernel practice keep state where it is true, after "Data is destiny": one home per truth, chosen by who may write it, everything derived computed from it (d-fd38bffc). - From the review of the previous round: the machine key and the user folder (always absolute, a key this user alone holds), prerelease versions read from HEAD, the plugin guide's corrected numbers, changed tracked links kept in a change, the store's hostile-input tests. - Work orders for what this round found and left: versions written by the build (w-d112a3e4), refutations derived from run records (w-f50ec192), measured numbers in docs (w-7f9dbfb0), a question-counted structure budget (w-77d2fe8f), re-closing a defect whose guard was retired (w-fdc00207), practice delivery attributed to the subagent that ran a command (w-9c70b73f), the Journal tab across worktrees (w-4c76c5ea). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…parser alone The four slots a plugin could fill to read its language's text by hand (source, declares, topLevel, kept) are gone from the plugin interface, pluginApi 4 (d-a59ee38f, w-8e253e9e). Nothing but test fixtures filled them: the four bundled language plugins and mnemion's Swift plugin all read through treeSitter. - A plugin of any pluginApi version that fills one is refused, naming the slot and how to read the language through treeSitter; one that fills none (convex, quint, declared) loads as before (OLDEST_PLUGIN_API stays 1, d-881c0b46). - The parser-derived readings are asked through parsedOf; syntaxOf serves the five slots that remain (entrances, interfaces, notice, lists, boundaries), so the type checker refuses a read of a removed slot (d-581051d3). The bundled manifests name pluginApi 4 (d-cfc26b51). - A test reads every non-test module of src and fails on any read of a hand-written slot, a cast among them; the fixtures that filled the slots read a made-up language through Python's parser (fixtures/parser- plugin.ts). Refuted by a kept read put back in keptModules. - The plugin guide, its claims test and the bullets that described the slots say what is now true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the patch cannot write; harden the dead-end alarm The blind review of 2558929, fixed as one round (d-a5c35add): a check never trusts input the thing it checks controls. - The parse store keeps each kept parse as a file of its own, named by the text's hex digest under the parser's fingerprint, written whole under a temporary name and renamed into place, never written again, as git keeps a loose object. A reading opens only the files of the texts it reads and holds no store in memory; nothing merges, reloads or locks. A parse read is stamped at most once a day, and a warm-up sweeps, once a day, what no process has read in fourteen days, temporary files of writes that died, discarded stores and dead fingerprints. The store is used only where every folder and link on its path, as written and as followed, is the user's or the system's and none others may write unless sticky; each read checks the parse's folder and file. Two warm-ups at once share the work in orders of their own. PostHog's 19,902 Python files: 32 s first warm-up, 2.0 s the next, mass 3.4 s. Two bullets retired (d-320d365d, d-e3e40b61); df-ef109f3e, df-d3eacab6, df-a05047c4, df-f1f4499c, df-fd915434 closed by guards. - The TypeScript grammar's build reads upstream's corpus from the pinned clean tree (tree hash checked, replace objects ignored), refuses a patch touching anything but define-grammar.js and scanner.h, and keeps Coherence's expected trees in grammars/tree-sitter-typescript/corpus, outside the patch. compare.mjs holds the parsers to every declared expected tree, one region per named form; the member-named-in query covers exactly the names the scanner acts on, methods included. Both parsers rebuild byte for byte. - The prerelease workflow splits into a read-only build job and a release job that alone may write; its smoke check runs plugin check from the installed tarball; a failed ls-remote stops the cut; its test is a lint of the file's shape and says so. The release job has not run. - The dead-end alarm counts every defect after a component's first guard, open or closed, and names a component whose arrivals rise; an unclassified defect counts as a class of its own; --component must own the defect's files; only an acknowledgement carrying the owner's words restarts the count; one window; the journal across worktrees is read whole, deduplicated by bytes. A practice may fire on a defect's class: keep state where it is true fires on duplicated-fact. - An ejected copy of a 1.10 plugin is told to eject again from this release; an interfaces table states facts alone, its readings coming from the parse; the text-scan test of the slots is retired for the registry's refusal (d-a1045837, d-e0d78a54). - The src/plugins dead end, escalated (e-24d456c1), acknowledged by the owner: "the dead end was addressed through redesign" (ak-6ae550c5). - Open: a leak-guard flake seen once under the full suite (df-e8424adc). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the alarm for a helpful agent - Every parse and query of a text stops past a fixed count of the parser's own progress calls, the same on every machine: a text past it reads as matching nothing, is kept nowhere and orient names it. A 12 MB file of one-line statements aborted the parse runtime and with it every later parse; PostHog's largest source file uses a tenth of the bound. A parse cut short resets the parser, which would otherwise resume it. - Import prefixes are spelled by walking a specifier's ancestors, not by scanning every prefix in the file: 16,000 grouped Rust uses, 14.6 s to 245 ms. - The parse store: a store inside the repository being read (a cache set inside a checkout) is not used for it; a folder only the user's own personal group may write counts as the user's (Debian and Ubuntu's default); orient says when the store is off and why; a parse too large to read back is never kept; a read stamp that cannot be written loses no parse; a sweep dated ahead is no sweep; temporary files are swept wherever the store writes; the warm-up reads no file whose real path leaves the project. Tests for the fingerprint's runtime and source, the path walked as written, sampling over the whole pass and the 32 MB bound. - A misread alarm: a plugin's queries may capture @misread on a node valid source never holds; the TypeScript plugin's capture a reserved word read as a name outside import and export names, and orient names the word and its line. Coherence evaluates #not-parent-type? and refuses any other predicate tree-sitter leaves unevaluated. Over 171,579 files, error-free trees held no such name elsewhere. - The grammar comparison's claim says it holds over its inputs alone; a corpus case no intended difference names must read as the stock parsers read it; in and instanceof before a parenthesis join the corpus. The prerelease smoke step checks each copy of the TypeScript parsers in the tarball against parsers.sha256. - The dead-end alarm serves an agent that wants to work helpfully (d-9d919dd8): a defect must say where it lies; answering verbs resolve ids in every worktree; a retracted defect counts nowhere; paths are normalized before ownership; spec --check reports an unreadable journal file rather than crash; orient is silent with no dead end; reading every worktree's journal goes through an index in the user's cache (about 300 ms to 105 ms here). A whole session start still stops on an unreadable file in its own journal (u-561ee937). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…point The ejected 1.10.1 fixture holds a second typescript.ts declaring SERVER_BIN, so the chokepoint named by file name alone was not run in CI's checks job. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every bundled language plugin now reads its text through a tree-sitter parser, and the parses that make this affordable are kept in the user's own cache, one file each. Merging this releases 1.11.0: the Release workflow publishes it to npm as
latest.What changes
treeSitter { parser, queries, resolve }, and the core derives every reading of the language's text from one parse.source,declares,topLevel,kept) are removed at plugin interface 4.import('x').T<U>and its kin, members and statements beginning within, and a bare&in JSX.grammars/tree-sitter-typescript/build.shbuilds both parsers with no network, from inputs checked by digest. It then compares stock and patched over upstream's corpus, Coherence's own corpus and this repository's source. CI'stypescript-parsersjob rebuilds them byte for byte.@misreadquery catches a reserved word read as a name in any file Coherence reads, and orient says so.$XDG_CACHE_HOME/coherence/parses, else~/.cache), never in a project.plugin checkgains three duties: answers agree, the language server agrees, and every plugin reads one reference project the same way. Also new:plugin shapes,plugin calibrateandplugin compare.spec --check, orient and the convergence reading name a component that keeps collecting defects across classes and rounds, and ask a human whether to redesign it. The journal is read across every worktree, and a defect must say where it lies. The alarm is built to help an agent that wants to work well notice a dead end; it is not a defense against an agent gaming its own records..github/workflows/prerelease.yml. A read-only build job checks the commit, packs the tarball, checks its parsers againstparsers.sha256and runsplugin check; only the release job can write.Review
Eight rounds of blind review ran against this branch. The parse store collected 26 defects over the first rounds, each fixed at the site the reviewer found, until the dead-end alarm named it. It was then redesigned: first moved out of the project, then made one file per parse. The owner acknowledged the dead end as addressed by the redesign (ak-6ae550c5).
The last review (of 766fba1) found shallower faults, each fixed locally in 9887d0f:
Known
spec --checkreports it instead (u-561ee937).prerelease.yml's release job has not run yet.({ a }?: T) => U;importOriginal<typeof import('x')>();inafter another member.Testing
npm test: 821 pass, 0 fail, 2 skipped (environmental).spec --check: 0 problems.lexicon:check: 0 rejected names.build.sh: both parsers rebuilt byte for byte; every difference from stock is intended.🤖 Generated with Claude Code