@meada/meada 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,709 @@
1
+ # Changelog
2
+
3
+ All notable changes to Meada are recorded here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project follows
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0] - 2026-10-30
10
+
11
+ The tree declares `1.0.0`: this release raises the workspace, the `meada-core` pin, the Dockerfile,
12
+ the compose defaults and the Helm chart from `0.1.0`, and the `v1.0.0` tag follows its merge on
13
+ main. Publication is still ahead and belongs to the maintainer under
14
+ [#154](https://github.com/ClaudioMascaro/meada/issues/154): `cargo publish` of the crates (core
15
+ first), approval of the staged npm package with 2FA, and publication of the GitHub draft release,
16
+ which triggers the OCI image and Helm chart workflow.
17
+ Release notes and the scope evidence checklist are available in
18
+ [pt-BR](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.0.0.md),
19
+ [English](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.0.0.en.md) and
20
+ [Spanish](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.0.0.es.md).
21
+ The [1.x stability promise](https://github.com/ClaudioMascaro/meada/blob/main/docs/site/en/stability.md)
22
+ starts at publication. The [#32 tracking checklist](https://github.com/ClaudioMascaro/meada/issues/32)
23
+ still needs the post-publication evidence.
24
+
25
+ ### Added
26
+
27
+ - Public fixture benchmark (issue #149): release-profile index/reindex timings, root and
28
+ workspace index sizes, and default-answer/tool-list token estimates in every PR/main CI
29
+ summary and retained JSON/Markdown artifact. Timings are informational.
30
+
31
+ - The English user guide and README (#150, spec #32): `docs/user-guide.en.md` translates both
32
+ halves of the pt-BR guide section by section (sections 1 to 11) with the same neutral examples
33
+ and links the English stability page; `README.en.md` now links it instead of the pt-BR guide.
34
+ No code, default dependency or golden changed.
35
+ - The Spanish user guide (#151, spec #32): `docs/user-guide.es.md`, sections 1 to 11 of the pt-BR
36
+ guide with the same structure and neutral names, linking the Spanish stability page. The Spanish
37
+ README links it instead of the Portuguese guide, and the three READMEs link the stability page
38
+ from the Status section. No code, default dependency or golden changed.
39
+ - The output grammar reference (#145, spec R1): `docs/reference/output-grammar.md`, in English like
40
+ the MCP surface, specifies every line kind of `search`, `context` and `trace`, the link notation
41
+ with its level and reason, the levels in order, the contract identifiers (`http::`, `http::ANY::`
42
+ for a provider of every method, `channel::`, `package::`, `resource::`), the `search` kinds, the
43
+ chain footer, the cut note and the token estimate, and tells readers to skip line kinds and
44
+ fields they do not know. Its tables are the grammar check's input: `tests/it/grammar.rs` matches
45
+ every line of every rendered-answer golden against the line kinds of its tool and fails naming
46
+ the golden and the line, fails on a documented line kind no golden shows, and holds the
47
+ document's levels, entry kinds, open item kinds and `search` kinds to the code's. The stability
48
+ document links it. No output changed; new goldens pin the answers only inline assertions covered (`no symbol
49
+ matches`, `no resource matches`, the server's `index behind the mirror`, and `trace` with no
50
+ start, several symbols, several call sites or a clean working tree).
51
+ - The pt-BR user guide, second half (#147, spec #32), in `docs/user-guide.md` (sections 8 to 11):
52
+ each contract kind (HTTP routes, declared resources and gateway prefixes, OpenAPI and AsyncAPI
53
+ documents, channels with the limit that broker clusters are not modelled, packages), each 1.0
54
+ language pack (TypeScript and JavaScript, Python, Go, Rust) with its frameworks, clients,
55
+ environment reads, manifests, channel clients and known limits (including that Rust calls inside
56
+ macros are not indexed), shape drift, and communities and processes. Java, Kotlin, C# and Swift
57
+ are named only as planned Release 2 work. No code, default dependency or golden changed.
58
+ - The pt-BR user guide, first half (#146, spec #32), in `docs/user-guide.md`: installation through
59
+ every channel (Cargo, prebuilt binary, shell installer, `npx @meada/meada`, container), MCP setup with
60
+ `npx @meada/meada mcp` and the three tools with their parameters, the `meada.toml` reference (every
61
+ table and key), decisions and deciders (protocols, environment variables, what is sent,
62
+ privacy), every CLI command and the export. The READMEs in all three languages gain the
63
+ installation channels, first steps, MCP setup and a 1.0 status section with the stability
64
+ promise. No code, default dependency or golden changed.
65
+ - Surface goldens (#144, spec #32): `tests/golden/mcp.tools.json` holds the MCP tool list (names,
66
+ descriptions and parameter schemas of `search`, `context` and `trace`), checked beside the
67
+ 1,000-token limit of the descriptions, and `tests/golden/cli.help-all.en.txt` the English help of
68
+ every command of the default build. A test pins the default token budget of 2,000. Both
69
+ goldens change only with `MEADA_BLESS=1`.
70
+ - The stability document (#148, spec #32), `docs/site/{pt,en,es}/stability.md`: the surface 1.x
71
+ freezes (the MCP tools, the output grammar, CLI commands and flags, the `meada.toml`,
72
+ `meada.decisions.toml` and `meada.workspace.toml` schemas, the export), what is breaking, what is
73
+ minor, what is not frozen, and the review gate. The READMEs and the site home pages link it.
74
+ - `search`, `context` and `trace` read from each index its contract rows and only the symbols,
75
+ calls and communities of their answer (#396, **Partial export**), instead of every row of every
76
+ repository. Answers are the same bytes; on junit5 a `search` or `context` peaks at about 40 MB
77
+ instead of 170 to 190 MB and answers in about 0.3 s instead of 1 to 1.4 s. The index gains
78
+ seven lookup indexes (about 40% larger on junit5) and its schema version changes, so existing
79
+ indexes are rebuilt. `meada export`, `status` and the decision report still read every row.
80
+ - A Meada skill for agents, `skills/meada/SKILL.md`: when to reach for `search`, `context` and
81
+ `trace`, how to read each level, and that a missing caller is unproven. The READMEs and the
82
+ site's MCP page show how to install it.
83
+ - Per-channel install and MCP setup: the READMEs open with one row per channel (npx, Cargo, shell
84
+ installer, archive, Docker) with its install line and MCP server command, and gain a Docker MCP
85
+ line that mounts the folder holding the repository at the same path and runs without a network.
86
+ `scripts/container-smoke` runs that line as a stdio client.
87
+ - The site's Deploy page (`docs/site/{pt,en,es}/deploy.md`) covers Docker, Compose and Helm, and
88
+ the chart gains `values-minimal.yaml`, which `scripts/helm-check` renders.
89
+
90
+ ### Changed
91
+
92
+ - For `meada-core` crate users: the export's structs (`Export` and each of its pieces, with
93
+ `Shape` and `Drift`) are `#[non_exhaustive]`, so a field added in 1.x is a minor change. Build
94
+ one with `T::default()` and named field assignments, or, for a struct with a field that has no
95
+ default (`Document`, `Import`, `Link`, `Process`, `Step`, `Stale`), with `T::new` taking every
96
+ field in declaration order (`Shape::new` takes the source, the rest set after it). A struct
97
+ literal or an exhaustive pattern of these types outside `meada-core` no longer compiles. No
98
+ output, golden or exported byte changed.
99
+ - The stability promise (spec #32) lets 1.x grow the MCP surface. In
100
+ `docs/site/{pt,en,es}/stability.md` and the three READMEs, these are minor changes: adding an MCP
101
+ tool while the tool list stays within its 1,000-token budget, adding an accepted value to an
102
+ existing parameter (a new value of `changes`) and adding a field at the end of an existing line
103
+ kind. Removing or renaming a tool or parameter and changing what an existing one means stay
104
+ breaking. ADR 0008 is amended: three tools is where the surface started, not a ceiling.
105
+ - `SECURITY` (pt-BR, English and Spanish): the latest published 1.x version receives security
106
+ fixes, which ship as a patch or minor release.
107
+
108
+ ### Fixed
109
+
110
+ - Console GitHub grant (#496): a session's GitHub grant and its state (`unread`, `current`,
111
+ `expired`) are read from the same permissions set at the same instant, so a session never shows
112
+ `expired` with a grant read while the set was fresh.
113
+ - Release preparation keeps the GitHub release in draft state for the maintainer to publish.
114
+ A pinned cargo-dist regeneration helper compares the entire workflow after the explicit
115
+ draft policy; OCI publication follows the human `release: published` event.
116
+
117
+ ### Prepared
118
+
119
+ - The v1 scope: HTTP, declared resources and gateway paths, OpenAPI/AsyncAPI, channels and
120
+ packages; levels and cross-repository chains, recorded decisions with optional deciders,
121
+ shape drift, TypeScript/JavaScript, Python, Go, Rust, communities and processes.
122
+ - The R1 stability promise, normative MCP output grammar, surface goldens, complete user
123
+ references and public-fixture CI benchmark. Fixture timings are informational.
124
+ - Configured Cargo, binary, shell, npm and OCI distribution. Configuration is not evidence
125
+ of actual publication or a successful published-installer smoke check.
126
+
127
+ ### Acceptance
128
+
129
+ The [public #152 receipt](https://github.com/ClaudioMascaro/meada/issues/152#issuecomment-6379316350)
130
+ retains both complete runs on AMD Ryzen 7 5825U, 16 logical CPUs, 7.16 GiB RAM,
131
+ Ubuntu 24.04.5 LTS, x86_64. The measured build was
132
+ `9b99c3a4091b6c1b2c590c43059763f25b6987ef`, `meada 0.1.0`, not every later documentation head.
133
+
134
+ | Metric | Target | First complete run | Complete rerun |
135
+ | --- | --- | --- | --- |
136
+ | Cold configured-workspace index | <= 7 s | 12.680 s, not met | 2.711 s, met |
137
+ | Root index size | <= 37 MB | 21.057536 MB, met | 21.057536 MB, met |
138
+ | Single-file configured-workspace reindex | <= 1 s | 1.346 s, not met | 1.152 s, not met |
139
+ | Compact MCP `tools/list` result | <= 1,000 tokens | 622, met | 622, met |
140
+ | Largest default answer among 11 queries | <= 2,000 tokens | 1,996, met | 1,996, met |
141
+
142
+ MB means 10^6 bytes; tokens are ceil(UTF-8 bytes / 4). Public fixture peers supplement the
143
+ private workload; the receipt does not claim every feature naturally occurs in the private root.
144
+ The [rerun of 2026-10-30](https://github.com/ClaudioMascaro/meada/issues/152#issuecomment-6531862493)
145
+ on main `1d648ad6` uses a reconstructed workspace (not directly comparable) and meets four of the
146
+ five targets: cold index (medians 5.586 to 6.625 s, <= 7 s), root index size (31.883266 MB,
147
+ <= 37 MB), `tools/list` (643 tokens, <= 1,000) and largest default answer (1,999 tokens,
148
+ <= 2,000). The single-file reindex (<= 1 s) met the target in the two quieter runs (0.99 and
149
+ 0.931 s) and missed it in the two runs at a load average near 3 (1.068 and 1.123 s). The
150
+ maintainer [waived the reindex target for 1.0.0](https://github.com/ClaudioMascaro/meada/issues/350#issuecomment-6532716065),
151
+ recorded on [#350](https://github.com/ClaudioMascaro/meada/issues/350).
152
+
153
+ Known limit: the single-file reindex sits near 1 s and exceeds it under load. #350 stays open for
154
+ 1.x, with the goal of 1 s with headroom under ordinary load; a speedup changes no output, so it
155
+ ships as a patch or minor release. Publication is done separately by the maintainer under
156
+ [#154](https://github.com/ClaudioMascaro/meada/issues/154).
157
+
158
+ ## [0.1.0] - 2026-10-30
159
+
160
+ The first release: the trunk of the roadmap (ADR 0003) and every spec merged since, with
161
+ identity automation (ADR 0016, #319) and named workspaces (ADR 0020) landing on the release day.
162
+ The trunk's detailed entries are in [docs/releases/0.1.0.md](https://github.com/ClaudioMascaro/meada/blob/v0.1.0/docs/releases/0.1.0.md);
163
+ the two later specs are listed below in full. Prebuilt binaries cover Linux and macOS on x86_64
164
+ and arm64 and Windows on x86_64; Windows arm64 waits for a toolchain that builds it.
165
+
166
+ ### Added
167
+
168
+ - TypeScript and JavaScript indexing with tree-sitter (`.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`,
169
+ `.cjs`): definitions, imports (relative paths, `index` resolution, `tsconfig.json` `paths`)
170
+ and calls, each with a level (`exact`, `inferred` or `ambiguous`). A call through a local
171
+ binding never resolves `exact` to the definition it hides.
172
+ - Python language pack (spec #24): definitions, imports (relative, packages, `import *` with
173
+ `__all__`, source roots from `pyproject.toml`) and calls, with receivers resolved through
174
+ `self`, annotations, constructor calls and the method resolution order. The main guard and
175
+ `[project.scripts]` targets are program entry points.
176
+ - Go language pack (spec #25), with no Go toolchain: functions, methods, structs and interfaces;
177
+ imports through the module path of the owning `go.mod` or a local `replace`; one scope per
178
+ package directory; build constraints for a fixed `linux/amd64` target; method calls through
179
+ the receiver types the source writes; `func main` of each `package main` as an entry point.
180
+ - Rust language pack (spec #30), with no Rust toolchain: crates built from their roots through
181
+ `mod` declarations; `use` declarations with renames, globs and `pub use` re-exports; path and
182
+ method calls resolved through the module tree and written types, a type from outside the
183
+ repository staying opaque; only the default configuration of a crate, for a fixed `x86_64`
184
+ Linux target and its default features; `fn main` of each binary target as an entry point.
185
+ - Java language pack (issues #84, #85, #91), with no JDK or build tool: package-qualified types
186
+ and signatures, overloads narrowed by argument count, package and static imports, calls
187
+ through fields, parameters, locals, return types and supertypes, read per class `family`, and
188
+ `public static void main` as an entry point.
189
+ - Kotlin language pack (issue #95), with no Kotlin compiler: `.kt` and `.kts` files with classes,
190
+ objects, companions, extension functions and properties; single, aliased and star imports;
191
+ calls `exact` when the argument count leaves one function; Kotlin and Java files of one
192
+ repository call each other.
193
+ - C# language pack (issue #107), with no .NET SDK or MSBuild: `.cs` files grouped into projects
194
+ by SDK-style `.csproj` files, namespace-qualified and `partial` types, `using` in all its forms
195
+ (`global`, `static`, aliases, a project's `<Using>` items and implicit usings), what referenced
196
+ projects pass on and the `Directory.Build.props` files MSBuild imports.
197
+ - Swift language pack (spec #29, #117), with no Swift toolchain or Xcode: each SwiftPM target is
198
+ a module; symbols named with their argument labels and extension members under the extended
199
+ type; calls narrowed by labels, `exact` on a receiver of written type; a `@main` type and a
200
+ `main.swift` start a process.
201
+ - HTTP contracts across repositories. TypeScript `fetch` consumers (client wrappers and base URLs
202
+ from the environment included) link to Next.js app router and Express providers; every link
203
+ carries a level and a reason, and a call whose URL cannot be read is an `unresolved consumer`,
204
+ never linked.
205
+ - HTTP providers in every other pack: FastAPI, Flask and Django URLconfs; `net/http`, gin, echo,
206
+ chi and gorilla/mux; axum, actix-web and Rocket; Spring MVC and JAX-RS; Ktor; ASP.NET Core
207
+ controllers and minimal APIs; Vapor and Hummingbird. Routers and groups are followed through
208
+ assignments, arguments, return values and imports, so a route is served under every prefix
209
+ around it; a prefix or mount Meada cannot read serves nothing.
210
+ - HTTP consumers in every other pack: `requests`, `httpx` and `aiohttp`; `net/http` and resty;
211
+ reqwest and ureq; RestTemplate, WebClient, `HttpRequest`, OkHttp and the `declarative client`s
212
+ OpenFeign and Retrofit (Java and Kotlin); the Ktor client; `HttpClient`, typed clients and
213
+ Refit; `URLSession`, Alamofire and AsyncHTTPClient. URLs fold from literals, constants,
214
+ concatenation and format strings, and a `client wrapper` is read at each of its call sites.
215
+ - Base URLs from the environment and configuration in every pack (`os.Getenv`, `std::env::var`,
216
+ `System.getenv`, `Environment.GetEnvironmentVariable`, `ProcessInfo`), Spring `@Value` with
217
+ `application.properties` and `application.yml`, and C# configuration with `appsettings.json`,
218
+ mapped to a `peer` through `base_url_env`. Meada never reads the value. Cross-language fixtures
219
+ link each language with TypeScript.
220
+ - Channels in Python, Go, Rust, Java, Kotlin and C#: Kafka, RabbitMQ, Amazon SQS, NATS, Redis
221
+ streams, JMS and Azure Service Bus clients are a `producer` or a consumer of a `channel`, linked
222
+ to the same channel in other languages, with the new broker kinds `jms` and `servicebus`. A
223
+ call counts only when its client traces back to the library; a name Meada cannot evaluate is
224
+ an `unresolved side`.
225
+ - Packages as contracts across seven `package ecosystem`s: npm (spec #22), PyPI, Go (spec #25),
226
+ Cargo (spec #30), Maven and Gradle (spec #26), NuGet (spec #28) and SwiftPM (spec #29).
227
+ A dependency on a workspace package links to it with its range flag, an import of the package
228
+ crosses into the provider's public declarations, `search` takes the kind `package`, and
229
+ `context` on an exported declaration lists its consumers in other repositories.
230
+ - Shape drift (spec #23, ADR 0009): each field a TypeScript or JavaScript consumer reads from a
231
+ response that the linked route does not return. Provider shapes come from an OpenAPI
232
+ `provider document`, a zod schema or the returned object literals, also through packages
233
+ (issue #175); consumer shapes from reads, casts and type annotations. `trace`, `context`,
234
+ `search` (kind `drift`), `meada status` and `meada export` show it.
235
+ - Communities and processes (spec #31): groups of symbols that call each other, found with a
236
+ deterministic Leiden and named after their most common directory, and `entry point`s (`route`,
237
+ `channel`, `export`, `program`) whose call tree `trace` renders from `process::<identity>`
238
+ across repositories. `search` takes the kinds `community` and `process`, and `context` adds
239
+ a symbol's community and the processes it belongs to.
240
+ - The query surface: an MCP server over stdio with three read-only tools, `search`, `context` and
241
+ `trace`, answering compact English lines under a token budget; `context` names the span's
242
+ range on its first line and cuts the span text first. `search` with kind `duplicate` lists the
243
+ symbols whose text is the same in two or more places of the workspace.
244
+ - The `meada` command (`index`, `status`, `export` with byte-reproducible JSON, `mcp`), messages
245
+ in Portuguese or English after `LANG`, `meada.toml` with `[[peer]]` and `[serve]`, workspace
246
+ discovery through the `origin` remote, and a per-repository SQLite index in `.meada/`
247
+ refreshed on every query from the files changed on disk. `meada status` points to the new
248
+ `inference` issue form when a repository holds a shape drift or an `inferred` link.
249
+ - Server mode (spec #259, ADR 0011): `meada mcp --listen` serves the three tools over MCP
250
+ streamable HTTP, one endpoint per repository, from the mirrors a `workspace manifest` lists;
251
+ indexes are refreshed by command, never by the server, and a reverse proxy admits the clients.
252
+ - Cloud modules (ADR 0012), cargo features off by default and all enabled by `cloud`: the shared
253
+ Valkey connection; the `snapshot store`, where `meada snapshot publish` uploads a `generation`
254
+ with BLAKE3-checked bundles and `meada snapshot pull` extracts it as hostile input; serving
255
+ generations with `--generations`, pinned at `/<identity>@<generation>`; the generation pointer
256
+ and retained generations in Valkey; and the `refresh lock` with its `fence`, never swapping a
257
+ `node` to a lower one.
258
+ - Operations on generations (ADR 0014): `meada snapshot pointer set`, `retain` and `drop` and
259
+ `meada snapshot fence recover` (#299, #300), a named lock holder, and the `heartbeat` each
260
+ `node` writes to Valkey after every pull round.
261
+ - OIDC admission (ADR 0012, feature `oidc`): the server becomes an OAuth 2.1 resource server
262
+ that checks a bearer JWT against the issuer's JWKS and bounds every answer to the identities
263
+ its claims, or its groups through `[oidc.groups]`, grant (#290, #291).
264
+ - GitHub App credentials (ADR 0013, feature `github-app`): `meada github-app credential` is git's
265
+ credential helper for the indexing job, minting installation tokens cached in Valkey and
266
+ skipping throttled installations.
267
+ - Workspace versions (spec #293, ADR 0014): with `[workspace] source = "store"`, the
268
+ `[[repository]]` entries live as immutable documents in the snapshot store, managed with
269
+ `meada workspace import`, `list`, `show`, `apply` (under the refresh lock, rolling back by
270
+ applying an older one) and `pull`.
271
+ - The management `console` (spec #293, ADR 0014, feature `ui`): `meada ui --listen` serves a
272
+ static Vite, React and TypeScript front end and a JSON API, with OIDC sign-in by authorization
273
+ code with PKCE S256, `viewer` and `operator` roles, operational pages for fleet, store,
274
+ repositories, GitHub App and admission, a query playground, code graph views, and operator
275
+ writes with one audit line each, in Brazilian Portuguese and English. The workspace editor
276
+ and version history (issue #310) validate entries and diff versions in the browser through
277
+ the shared WebAssembly core.
278
+ - Team ownership (ADR 0015): a workspace entry may name its `owner` team, and a `team operator`
279
+ may save and apply changes to its teams' entries alone; any other change is refused naming
280
+ each entry and its reason. The editor marks refused changes as they are typed, and the
281
+ console documentation gains a Teams section. The whole is additive, a minor change.
282
+ - Distribution: a cargo-dist release workflow building binaries for Linux, macOS and Windows on
283
+ x86_64 and arm64 with a shell installer, and an npm package `@meada/meada` (spec #32) staged
284
+ with each release for `npx @meada/meada`; multi-arch OCI images, default and `-cloud` (issue
285
+ #279), with the console's static files in the cloud image (issue #313); a Helm chart (#281);
286
+ Docker Compose examples (#280); and opt-in console profiles for both (issue #314).
287
+ - Documentation and community: README, CONTRIBUTING, code of conduct, security policy and issue
288
+ and PR templates in Portuguese, English and Spanish; a CI workflow; a multilingual
289
+ documentation site (issue #320); ADR 0020, recording the direction of spec S5.
290
+ - Every language pack and every manifest and configuration reader has a hostile-input probe
291
+ held to a time and size budget.
292
+ - Validation and operation of the named-workspace flow (#347, spec S5): a failure test that forces
293
+ the role check, the fetch/index and the local publication to fail in turn and shows the current
294
+ generation stays queryable, eligibility stays fail closed and a revoked grant never revives
295
+ (only a later complete permissions set restores it); the upgrade procedure (migrate to schema 8,
296
+ upgrade every binary before the first refresh that records a context, then configure), the
297
+ failure table and the acceptance map on the named-workspaces page in Brazilian Portuguese,
298
+ English and Spanish; `[catalog]` and `[workspaces]` in the Compose bootstrap examples; and the
299
+ Helm values `modules.workspaces` with `values-workspaces.yaml`, which put those sections (and
300
+ the `[ui]` block the job needs) in the console's and the job's bootstrap and never a node's.
301
+ The measurement against a real GitHub organization (#338) stays open and does not gate S5. No
302
+ code, default dependency or golden changed.
303
+ - The proposal server (#346, ADR 0022, feature `proposals`, enabled by `cloud`): `meada workspaces
304
+ mcp --listen <addr> --workspace <bootstrap>` with `[proposals]` (`public_url`, `audience`)
305
+ serves CLI agents four read-only MCP tools over the console's own named-workspace functions:
306
+ `catalog` (the repositories the caller may select), `workspaces` and `show` (the workspaces it
307
+ may see, with their `seq`) and `propose`, which validates manifest text as a new workspace or a
308
+ change and returns the canonical manifest, the diff against the base, diagnostics, each named
309
+ identity's eligibility, the refusals the console would give, the effective configuration,
310
+ `applicable` and the base, storing nothing. Identity, login, grant and role come from a bearer
311
+ token for `[proposals] audience`, which no node or console accepts and which accepts no
312
+ node's or console's token; no tool takes an argument naming an actor, a role or a grant, and
313
+ repository hints from an agent's own GitHub read MCP change no result. Every Postgres session
314
+ of the server is read-only, it calls no GitHub, node or identity provider API and writes no
315
+ audit record, store object or Valkey key. Inputs and answers are bounded (a body of 80 KiB, a
316
+ manifest of 64 KiB, an answer of 192 KiB, 32 calls in flight). The node's MCP server, the
317
+ console and the default build are unchanged.
318
+ - Guided authoring of named workspaces (#345, ADR 0021 "As built (#345)", feature `workspaces`):
319
+ the console edits the manifest of a workspace the subject operates through form controls
320
+ (repositories from the catalog, serve settings, resources, peers and environment-variable
321
+ names) that are one document with the manifest text, both going through `meada-core`'s
322
+ WebAssembly. It shows each entry's eligibility, ingestion and effective configuration in text,
323
+ the diff against the stored version, and freezes the reviewed payload until the person
324
+ confirms; server refusals (`entries_refused`, `stale_base`, a lost operator role) are shown as
325
+ worded and the catalog is read again. `namedDiff` and `namedChanged` join the WebAssembly
326
+ exports. Viewers get no mutation control. No server route changes; nothing changes without
327
+ `[workspaces]`.
328
+ - Context-specific configuration of named workspaces (#344, ADR 0021 contract 6, feature
329
+ `workspaces`): `GET /api/v1/workspaces/<id>/effective[?version=]` shows, per entry the caller
330
+ reads, where its configuration comes from (the repository's own `meada.toml` wins whole, else
331
+ the workspace's `serve`, `resource` and `peer` blocks, else nothing), the blocks that are
332
+ ignored, whether the repository is indexed, pending ingestion or excluded, and diagnostics
333
+ (`ignored_by_repository`, `unknown_until_ingested`, `excluded_no_sponsor`, `peer_missing`,
334
+ `documents_not_indexed`). `POST /api/v1/workspaces/effective` shows the same view for manifest
335
+ text before it is saved and stores nothing; creation, save and apply answers carry the same
336
+ `diagnostics`, so an ignored declaration never looks plainly applied. Two workspaces that
337
+ share a repository keep their own peers, resources and serve hosts: the configuration is applied
338
+ when answering and never enters a bundle, so a change of it re-indexes nothing and a pinned
339
+ generation keeps what it recorded. The decision is `meada_core::effective`, also exported to
340
+ WebAssembly (`namedEffective`). The console's workspace page shows the view in text and has a
341
+ text editor for the manifest of a workspace the subject operates. Nothing changes without
342
+ `[workspaces]`.
343
+ - The version lifecycle of named workspaces (#343, ADR 0021 contract 4, feature `workspaces`):
344
+ `POST /api/v1/workspaces/<id>/versions` saves a version without moving anything (an operator
345
+ submits the entries it reads and the version stored keeps the ones it cannot read; the
346
+ platform administrator submits the whole manifest), `.../apply` applies a stored version (a
347
+ version that was current before is a rollback), `.../rename`, `.../delete` (versions and
348
+ history are kept) and `.../operators` (the platform administrator delegates; a workspace keeps
349
+ at least one operator). Every write carries the `base` it read: a stale base, a revoked role, a
350
+ refused entry or a version of another workspace is refused and changes nothing, and the
351
+ transaction rechecks authority, base and the eligibility of what the operation adds or changes
352
+ against the newest permissions set. Only an operator of the workspace or the platform
353
+ administrator writes; a viewer is a 403 and a caller who cannot see the workspace gets the 404
354
+ of an unknown id. `GET .../versions`, `.../versions/<version>?against=` (with a diff) and
355
+ `.../history` read them under the same discovery rule. Each operation is one audit record
356
+ (`workspaces.save`, `.apply`, `.rollback`, `.rename`, `.delete`, `.operators`) with the
357
+ workspace and base. `meada workspaces list|show|versions|diff|create|save|apply|rename|delete|operators` are
358
+ the command-line twins (the platform administrator, `cli` audit records). Migration 8 adds
359
+ `workspace_versions.entries`: run `meada postgres migrate` before upgrading the binary. Without
360
+ `[workspaces]` nothing changes.
361
+ - The first named workspace of spec S5 (#342, ADR 0021 contracts 2 to 5, cargo feature
362
+ `workspaces`): `[workspaces]` (`mirrors`, an absolute root; `max_workspaces`, default 200, 1 to
363
+ 2000; `max_entries`, default 100, 1 to 500) needs `[ui]` with `operations = true`,
364
+ `[oidc.github]`, `[catalog]` and `[workspace] source = "store"`. An admitted subject whose
365
+ GitHub login holds an accepted role on every selected repository, directly or through a group,
366
+ creates a workspace with `POST /api/v1/workspaces`; `GET /api/v1/workspaces` and
367
+ `GET /api/v1/workspaces/<id>` list and show it to whoever's own grant reads every one of its
368
+ repositories (anyone else gets the one 404 of an unknown id), with `state` (`applied` or
369
+ `live`) and each entry's `ingestion` (`pending`, `ready` or `excluded`), never ready before a
370
+ generation records it. The creator operates it; group peers only view. The
371
+ decision is taken in one Postgres transaction against the newest permissions set (migration 7:
372
+ `workspaces`, `workspace_operators`, `workspace_versions`, `workspace_history` and a `context`
373
+ column on `permission_exclusions`; run `meada postgres migrate`); the version document is the
374
+ shared store's `workspaces/<version id>.json`. `meada workspace pull` also writes the contexts
375
+ file, `meada github-app roles` applies the sponsor rule (an entry no operator of its workspace
376
+ holds an accepted role on is left out before the fetch, `no_sponsor`, which is not a failed
377
+ fetch), and the repositories only named workspaces select are fetched, indexed and bundled once
378
+ at `<mirrors>/<identity>` (`meada workspace show --pulled` lists them). A generation records them
379
+ as `members` and the named workspaces as `contexts` (ids and digests in the generation id; a
380
+ deployment without named workspaces keeps every id), and a node serves
381
+ `/-/workspaces/<id>/<identity>` only to a token that reads every repository of the context (the
382
+ first segment `-` is reserved); the console's playground gains `workspace` and
383
+ `GET /api/v1/workspaces/<id>/repositories/<identity>/export`. The console has the workspaces
384
+ page (list, detail, creation from the catalog) and WebAssembly exports for the shared
385
+ rules. Save, apply, rename, delete and delegation (#343), per-context configuration (#344),
386
+ guided authoring (#345) and proposals (#346) are not built. Without `[workspaces]` every
387
+ process behaves as before; upgrade every binary, nodes included, before the first refresh that
388
+ records a context.
389
+ - The repository catalog of spec S5 (#341, ADR 0021 contract 1, cargo feature `workspaces`,
390
+ part of `cloud`): `[catalog]` (`allow` patterns on `[oidc.github] host`, `max_repositories`
391
+ 1 to 5000 with no default) makes `meada github-app roles` list, besides the workspace's own
392
+ repositories, those the Apps' installations cover (`GET /installation/repositories`, every page,
393
+ only for owners a pattern names) and `allow` admits, into the same permissions set with a
394
+ `source` on each repository (Postgres migration 6; run `meada postgres migrate`). A failed or
395
+ throttled listing, a body that is not the documented object or a candidate set above the cap
396
+ fails the run and writes nothing. The console gains `GET /api/v1/catalog` (bounded, opaque
397
+ pagination, `limit`, `after`, `q`) and `POST /api/v1/catalog/check`, answering only the
398
+ repositories the caller's login holds an accepted role on, direct or group-derived alike, with
399
+ the states `ready` and `pending` (`no_set`, `stale_set`, `missing_login`) and `unavailable`
400
+ without a reason, plus the repository catalog page; App coverage, group names in a token and
401
+ agent metadata alone grant nothing, and discovery creates no workspace, ACL or index. Without
402
+ `[catalog]` every process behaves as before. The cost of expanded coverage against a real
403
+ organization is not measured (#338 does not gate it).
404
+ - Spec S5 consolidated (#340, documentation only; nothing is implemented): ADR 0020 now holds
405
+ the accepted domain decision (platform administrator, workspace operator and inherited viewer,
406
+ creation eligibility from accepted repository roles, the frozen Y/A/B matrix, hidden discovery
407
+ for partial readers, revocation), ADR 0021 the contracts (catalog, selected entries, shared
408
+ ingestion membership, version lifecycle, query selection, effective configuration,
409
+ deterministic ids, migration and the slice graph #341 to #347) and ADR 0022 the authenticated
410
+ stateless proposal server. The glossary gains the terms, ADRs 0002, 0012, 0014, 0015 and 0016
411
+ carry dated amendments, `tests/fixtures/named-workspaces.json` is the Y/A/B table with a
412
+ `meada-core` test that checks it against the rules, and the named workspaces and roadmap pages
413
+ are updated in three languages. No serialized role, route, id, golden or default build changes.
414
+ - Identity automation for enterprise deployments (ADR 0016, spec #319), in the entries below: the
415
+ `postgres` and `directory` features and the `[postgres]`, `[directory]`, `[oidc] type`,
416
+ `[oidc.entra]` and `[oidc.github]` sections; `meada postgres migrate`, `meada github-app roles`
417
+ and `meada workspace show --pulled`; an entry's `added_by` and the `unattributed` and
418
+ `added_by_change` reasons of `entries_refused`; the session's `login`, `github_host` and
419
+ `github_grant`, the token check's `sources`; the audit and `GET /api/v1/audit`; the SCIM endpoint
420
+ under `/scim/v2/`, the `deprovisioned` refusal, the owner picker, `owner_missing` and `excluded`.
421
+ Under Spec R1's stability rule every one of them is additive: a minor change. Without the new
422
+ sections every process behaves as before, and the default build, the CLI help, the MCP surface
423
+ and every export and trace golden are unchanged.
424
+ - The identity automation documentation, in three languages: an enterprise identity guide (the
425
+ data layer, the audit, the provider type, the GitHub grant, additions under the provider, the
426
+ directory, Entra overage and Known ceilings), recipes for Entra ID, Okta and Keycloak, the
427
+ roadmap and diagrams with S4 delivered, and the architecture map's Known ceilings gaining the
428
+ login length and the audit's growth. S5 (#339), named workspaces and authoring through the UI or
429
+ MCP, stays planned.
430
+ - The Compose example gains `compose.postgres.yaml` (a Postgres 15 with TLS and the three
431
+ recommended roles, and a one-shot `meada postgres migrate` step that finishes before the job,
432
+ the console and the nodes), a `fetch-pulled.sh` for the job's refresh under `[oidc.github]`, and
433
+ commented `[postgres]`, `[oidc.github]`, `[directory]` and `[oidc.entra]` examples in the
434
+ bootstraps. The Helm chart gains `modules.postgres`, `modules.githubApp`, `modules.oidc.github`,
435
+ `modules.oidc.type` and `entra`, `modules.directory`, a migrate hook Job with pods that wait for
436
+ the schema, an example Postgres (`postgres.enabled`) and `values-identity.yaml`; the default
437
+ values render nothing of Postgres.
438
+ - `[oidc.github]`, the GitHub grant provider's table (ADR 0016): `host` (default `github.com`, a
439
+ lowercase host name), `login_claim` (required), `roles` (a non-empty array of distinct role
440
+ names of 1 to 100 characters with no control character, compared exactly with GitHub's
441
+ `role_name`; default `["read", "triage", "write", "maintain", "admin"]`) and `max_age_seconds`
442
+ (required, at least 60). It needs `[postgres]` and a build with `postgres`, each error naming
443
+ them; beside it `[oidc]` needs neither `identities_claim` nor `groups_claim`.
444
+ - The GitHub grant at admission (ADR 0016): nodes and the console with `[oidc.github]` keep the
445
+ newest permissions set in memory, read every 60 seconds without admission ever waiting on
446
+ Postgres, and a token reads the union of its claims grant and what its `login_claim` login (1
447
+ to 39 ASCII letters, digits, `-` and `_`, compared in lowercase) holds an accepted role on,
448
+ everywhere the grant is read: a node's admission, routing, answers and 404 lists, and every
449
+ bounded view of the console, the team operator role, the entry authorization and the token
450
+ check. The GitHub part grants for at most `max_age_seconds` past the set's `finished` on
451
+ Postgres's clock, then nothing, the claims grant unaffected; a machine token's `*` never
452
+ depends on Postgres. A node starts and serves without Postgres, and names a schema version it
453
+ does not know once on stderr. Every row read is checked as hostile input.
454
+ - `GET /api/v1/session` gains, with `[oidc.github]`, `login` (when the token has a valid one),
455
+ `github_host` and `github_grant` (`current`, `expired` or `unread`); `grant` is the union.
456
+ `POST /api/v1/admission/check` gains `sources`: `{"claims": "*" | [identities], "github":
457
+ [identities]}`, each sorted, from the console's cache. `GET /api/v1/admission` gains `github`:
458
+ the grant provider's settings, the grant's state and the newest set's id, `finished`, age, `max_age_seconds`,
459
+ repositories, rows and exclusions. The admission and session pages show them, and audit
460
+ records carry the subject's login.
461
+ - Additions under the GitHub grant provider (ADR 0015, ADR 0016): a team operator may add, for
462
+ its team, an entry of a repository on `[oidc.github] host` that its grant does not read yet.
463
+ The console's save sets the addition's `added_by` to the saver's login whatever the submitted
464
+ text says (and clears it on additions off the host), and the role check fetches the entry only
465
+ while that login holds an accepted role. Two refusal reasons join `entries_refused`, in
466
+ precedence order `outside_grant`, `unattributed` (an addition on the host without `added_by`,
467
+ or by a subject without a login), `ownerless`, `owner_change`, `added_by_change` (an edit
468
+ changing, clearing or setting `added_by`) and `not_your_team`. A save that adds an identity
469
+ the workspace already holds outside the grant is refused `outside_grant`, naming it as
470
+ submitted. The global operator's saves and the CLI keep `added_by` as written.
471
+ `authorize_entries` and `compose_entries` of `meada-core`, and their WebAssembly exports, take
472
+ the subject's login and the GitHub grant provider's host (none without the GitHub grant provider, answering as before),
473
+ and the editor marks the new reasons as it marks the others, in pt-BR and English, and shows
474
+ each entry's `added_by`.
475
+ - `excluded`: with `[oidc.github]`, `GET /api/v1/workspace` and `GET
476
+ /api/v1/workspace/versions/<id>` mark `excluded: true` on each entry of the version the newest
477
+ permissions set checked whose addition it left out, for those who see the entry; the field is
478
+ absent otherwise. The versions page and the editor mark those entries with the reason that the
479
+ adder holds no accepted role.
480
+ - `meada github-app roles --workspace <bootstrap manifest>` (features `github-app`, `postgres`
481
+ and `oidc`), the job's role check at every refresh: for each identity of the workspace on
482
+ `[oidc.github] host` it lists `GET /repos/{owner}/{repo}/collaborators?affiliation=all&per_page=100`,
483
+ every page, through the installation ADR 0013's selection picks, and replaces the permissions
484
+ set in Postgres in one transaction (what GitHub showed of each repository, its rows, every
485
+ collaborator listed with its `role_name`, and its exclusions with their reason), refused when a set with a higher `MEADA_REFRESH_FENCE` exists. With
486
+ `source = "store"`, every addition whose `added_by` holds no accepted role is left out:
487
+ written to `<index_dir>/workspace/excluded`, and `meada index`, `status`, `export` and
488
+ `snapshot publish` treat it as absent from the workspace, refusing to run, naming the role
489
+ check, when the file is missing or names another version. A 403 or 429 passes to the next
490
+ installation; every one throttled, a 5xx, a timeout, an answer past the size cap or a
491
+ `Link` header that leaves the repository's listing fails the run, which writes nothing. A
492
+ 404 or an owner no installation covers gives a warning and no rows. No App permission beyond
493
+ Metadata (read) is needed. The job's refresh becomes `workspace pull`, `github-app roles`,
494
+ the fetch of what `show --pulled` lists, `index` and `snapshot publish`.
495
+ - `meada workspace show --pulled --workspace <bootstrap manifest>` prints the version `meada
496
+ workspace pull` left on disk in the `[[repository]]` shape, without the entries the role
497
+ check excluded, for the fetch script; with a version argument it is a usage error.
498
+
499
+ - `added_by`, an optional key of a workspace version's `[[repository]]` entries beside `repo`,
500
+ `path` and `owner` (ADR 0016): the GitHub login that added the entry, 1 to 39 characters of
501
+ lowercase ASCII letters, digits, `-` and `_`. It is imported, stored, shown (`meada workspace
502
+ show` prints it right after `owner`) and pulled like `owner`, joins the version id and no
503
+ generation or bundle id, and nothing reads it to decide anything yet. An entry without it keeps
504
+ its version id. A bad value is an error naming the file, the line and the key, in a
505
+ bootstrap manifest's own `[[repository]]` entries (`source = "file"`) the key is an error
506
+ naming `source = "store"`, and a repository's `meada.toml` still rejects it as unknown.
507
+ - `[oidc] type` names the identity provider that issues the deployment's tokens (ADR 0016):
508
+ `generic` (the default), `entra`, `okta` or `keycloak`. None changes the admission, the grant or
509
+ any answer, and a bootstrap manifest without the key works as before; the console's `GET
510
+ /api/v1/admission` gains `"type"`, which the admission page shows beside the issuer. Any other
511
+ value, or one that is not a string, is an error naming the file, the line, the key and the four
512
+ values.
513
+ - `[oidc.entra] overage = "directory"` (ADR 0016): a Microsoft Entra ID token in more groups than
514
+ it can carry (`_claim_names` mapping `groups_claim` to a source, no `groups`) gets its groups
515
+ from the directory the identity provider pushes through the console's SCIM endpoint: the
516
+ `group_attribute` values of the groups whose members include the active user whose
517
+ `user_attribute` equals the token's `user_claim`. They replace the missing claim everywhere
518
+ `groups_claim` is read: a node's grant through `[oidc.groups]`, and the console's grant,
519
+ `[ui] operator_groups`, the team operator's teams, the session's `groups` and the token check.
520
+ It needs `[directory]` and `groups_claim`, each error naming the file, the line and the key.
521
+ Nodes and the console look a token up once at admission and keep the answer five minutes, per
522
+ `user_claim` value; a failed lookup is not kept, and with Postgres unreachable the token has no
523
+ groups, as before, with one stderr line. Meada never calls the source's endpoint. The console
524
+ still refuses a deactivated or deleted provisioned user as `deprovisioned` before any cached
525
+ answer is used. `overage = "ignore"` keeps today's behavior.
526
+ - `[oidc.entra]`, the settings only Entra ID needs, allowed under `type = "entra"` alone, with one
527
+ key: `overage = "ignore"` (the default), a token in overage having no groups, as before. Any
528
+ other value, and an unknown key, is an error naming the file, the line and the key.
529
+ - The data layer (ADR 0016): the `postgres` cargo feature, off by default and enabled by `cloud`,
530
+ and the bootstrap manifest's `[postgres]` section, which needs no other section. It names the
531
+ connection URL only through `url_env` (default `MEADA_POSTGRES_URL`) or `url_file`, plus
532
+ `ca_file`, `schema` (default `meada`), `pool_size`, `connect_timeout_seconds` and
533
+ `statement_timeout_seconds`. The URL is `postgres://` or `postgresql://` with a TCP host and no
534
+ query parameter (`sslmode` included); an error names the key, never the URL. A host outside
535
+ loopback always connects over TLS with its name verified, against `ca_file` alone when set,
536
+ else the system roots; a loopback host connects in plain TCP unless `ca_file` is set. Every
537
+ table lives in the schema `[postgres]` names. `[postgres]` in a build without the feature is
538
+ the error naming it. Postgres 15 and later.
539
+ - `meada postgres migrate --workspace <bootstrap manifest>` creates the schema when absent and
540
+ applies each migration up to the binary's version, each in its own transaction, under an
541
+ advisory lock keyed by the schema, so two runs serialize; it prints the version reached and
542
+ never lowers one. It ships migration 1, the schema's version. Every later connection refuses a
543
+ version the binary does not know: a lower one (an absent schema included) names `meada
544
+ postgres migrate`, a higher one names both versions.
545
+ - The directory (ADR 0016): the `directory` cargo feature, implying `postgres` and enabled by
546
+ `cloud`, and the bootstrap manifest's `[directory]` section, which needs `[postgres]` and
547
+ `[oidc]`: `token_env` (default `MEADA_SCIM_TOKEN`) or `token_file`, `user_claim`,
548
+ `user_attribute` (`userName` or `externalId`) and `group_attribute` (`displayName`, the
549
+ default, or `externalId`). Only the console reads the token, at start: shorter than 32
550
+ characters, unset or unreadable, it refuses to start naming the key, never the value.
551
+ `[directory]` in a build without the feature is the error naming it.
552
+ - The SCIM 2.0 endpoint: with `[ui]` and `[directory]` the console serves `/scim/v2/`, where
553
+ Entra ID's and Okta's provisioning create, read, filter, page, replace, patch and delete users
554
+ and groups, stored in the data layer (migration 3) as the provider sent them, never with
555
+ `password`. It admits only its own bearer token (no console token, and no request carrying
556
+ `Origin`), bounds a body at 1 MiB and a resource at 64 KiB, answers RFC 7644's errors with
557
+ their `scimType` and no echoed value, a 503 with Postgres unreachable, and the
558
+ `/ServiceProviderConfig`, `/ResourceTypes` and `/Schemas` documents. A deleted user leaves
559
+ every group and a revocation marker until it is provisioned again, active. Each write leaves
560
+ one stderr line, `scim: <method> <resource> <id>: <status>`.
561
+ - Deprovisioning in the console (ADR 0016): with `[directory]`, the token's `user_claim` is looked
562
+ up in the directory by `user_attribute` (`userName` ignoring case, `externalId` exact). A user
563
+ found inactive, or deleted and not provisioned active since, gets a 403 `deprovisioned` on every
564
+ route but `GET /api/v1/config`, whatever its role, and the console shows a deactivated-account
565
+ page. A user never provisioned is admitted. With the directory unreadable, reads are admitted
566
+ and a write is a 503 `audit_unavailable` before any audit insert, with one stderr line that
567
+ names the directory and never the claim. Migration 4 adds the directory's state row (the schema
568
+ version is now 4); a directory that had already lost its last group before the upgrade starts
569
+ with no group ever provisioned, so nothing is flagged until a group is provisioned again.
570
+ - The owner picker: `GET /api/v1/directory/groups?prefix=<text>`, for the global operator alone,
571
+ lists at most 100 group names starting with the prefix (compared exactly, sorted), and the
572
+ workspace editor offers them while the caret is inside an `owner = "..."` string.
573
+ - `owner_missing`: `GET /api/v1/workspace` and `workspace/versions/<id>` add `"owner_missing":
574
+ true` to an entry whose owner names no directory group, once a group was ever provisioned; the
575
+ versions page and the editor say so in text. `GET /api/v1/admission` gains the directory's
576
+ users and groups counts and the last SCIM write, which the admission page shows.
577
+ - The audit (ADR 0016): with `[postgres]`, every console write (`workspace.save`,
578
+ `workspace.apply`, `pointer.set`, `pointer.retain`, `pointer.drop`, `fence.recover`) and every
579
+ CLI twin of one (`meada workspace import` and `apply`, `meada snapshot pointer set`, `retain`
580
+ and `drop`, `meada snapshot fence recover`) leaves a record in `<schema>.audit` (migration 2):
581
+ who (subject, role, a team operator's owners), what (action and arguments), when (Postgres's
582
+ clock) and the outcome. The record is written as `pending` before the write touches Valkey or
583
+ the store, so a write whose record cannot be written is refused and changes nothing: the
584
+ console answers 503 `audit_unavailable`, the CLI exits 1 naming Postgres. Role refusals and
585
+ refusals under the lock are recorded too. The console starts with Postgres unreachable (reads
586
+ are served) and refuses to start on a schema version it does not know, as each CLI twin exits
587
+ 1. The global operator reads the records, newest first, through `GET
588
+ /api/v1/audit?before=<id>&limit=<n>` and the console's new audit page. Without `[postgres]`
589
+ every write behaves as before, and the stderr lines are unchanged in both cases.
590
+ - `meada status --workspace` with `[postgres]` prints `postgres: reachable, schema <name>
591
+ version <n>` or `postgres: unreachable (<reason>)`, a version refusal included, without
592
+ changing its exit code.
593
+
594
+ ### Changed
595
+
596
+ - The repository is a Cargo workspace (ADR 0014, #296, #297): the library crate `meada-core`
597
+ holds the manifest schema, the generation and version ids, the export's types, the query
598
+ results and shape drift, builds for WebAssembly for the console, and is published to
599
+ crates.io before `meada`. Every golden and message of the default build is unchanged.
600
+ - A refresh publishes the whole workspace or nothing (ADR 0012, #316), and a workspace of any
601
+ number of repositories opens and answers (the limit of eleven is gone).
602
+ - `context` and `trace` show the overloads of one method as one set, and a call that decorates
603
+ a definition (an annotation, an attribute, a decorator, a route attribute) is listed under
604
+ `annotations:` in `context` instead of among the callees.
605
+ - A Kotlin `HttpClient` held through more locals than `LOCAL_DEPTH` is now a consumer.
606
+ - The `decisions` `decider`'s default model is now `typesafe/jev-1.14`; `MEADA_DECIDER_MODEL`
607
+ still overrides it.
608
+ - The coding standards class each string table a language pack holds, and a test fails on an
609
+ unlisted one.
610
+
611
+ ### Fixed
612
+
613
+ - `meada mcp` answers about the client's first MCP root and falls back to its own directory
614
+ without roots (#192); a `roots/list` that times out after 5 s or fails answers about the last
615
+ root, or returns a tool error, instead of hanging or answering about the wrong tree (#282,
616
+ #285).
617
+ - TypeScript and JavaScript resolution: a call with type arguments under `await`, the `paths` of
618
+ a nested `tsconfig.json`, functions defined by assignment (`exports.y =`, prototypes, object
619
+ literal methods) and a name two `export *` give differently.
620
+ - Python resolution: nested `pyproject.toml` package roots, star imports and names bound again
621
+ (the last binding decides, `del` and a grown or computed `__all__` included).
622
+ - Java and Kotlin resolution: annotations written in full, method annotations through a base
623
+ from outside the repository, calls on another call's result, secondary constructors,
624
+ `expect` and `actual` classes, star imports, varargs, Java locals followed into their value,
625
+ separate field and method namespaces, and Maven or Gradle coordinates named by a property.
626
+ Ambiguous or unresolved OpenFeign and Retrofit methods are `open item`s that `meada decide`
627
+ resolves.
628
+ - C# resolution: types of enclosing namespaces, `internal` types, a qualified name two projects
629
+ declare, library names written in full, member reads between calls and overloads across
630
+ projects; `obj/` and `bin/` stay out of the index.
631
+ - Swift resolution: a module per package with `@testable import`, `typealias` receivers,
632
+ implicit members, capitalized function calls, outside member reads as `opaque outside`, Vapor
633
+ middleware groups and `if let` environment reads.
634
+ - Rust resolution: calls on another call's result, types brought by a glob import, a `mod` any
635
+ test build compiles, and broker clients read by path.
636
+ - A class whose outside bases are all platform types with `known outside members` resolves
637
+ calls to its own members at `exact` (ADR 0019).
638
+ - Spring and Retrofit contracts: an AMQP publish of a repository class, `@Value` fields beside
639
+ same-named locals, Gradle source sets outside `src/main`, Retrofit path rules, and `context`
640
+ on a shared artifact's class listing its calls in other repositories.
641
+ - What gets indexed: `node_modules`, `Pods`, Carthage `Checkouts` and minified files stay out,
642
+ `.meadaignore` is read like a `.gitignore`, `Package@swift-<version>.swift` is a manifest, a
643
+ large generated C# file is read whole (or named by `meada status`), and an invalid or
644
+ oversized config no longer stops indexing.
645
+ - Hostile input: crafted chains of re-exports, receivers, includes and static imports no longer
646
+ overflow the stack; folded values stop at a budget of 2^16 steps per file or 256 levels; a
647
+ manifest past 1 MiB and a provider document past 16 MiB are read capped, and a Spring YAML
648
+ past its key budget reads as empty.
649
+ - Performance: method chains, files of thousands of names, imports or definitions, Java local
650
+ chains, deeply nested Rust blocks and large C# project files no longer take time quadratic
651
+ or worse in their size, and a class family near 128 classes resolves the same whatever the
652
+ reading order.
653
+ - Console and fences: manifest groups and validation errors respect the viewer's grant, PKCE
654
+ redirects keep the issuer's query parameters, and fence recovery shares the fleet reader's
655
+ Valkey clock and heartbeat checks.
656
+ - Rust item macros (#398): the braced body of a `macro_rules!` of the repository whose first arm
657
+ takes `$($x:item)*` and writes each item back behind outer attributes only (tokio's
658
+ `cfg_rt! { pub mod runtime; }`) is read as items of the module invoking it: its functions,
659
+ types, `impl` blocks, `use` and `mod` declarations and the calls inside them, with spans into
660
+ the file. A `mod` in it reaches its file, and the `#[cfg(..)]` attributes the arm writes gate
661
+ every item under the crate's default features. A name defined several times qualifies only when
662
+ all definitions agree; any other macro stays unread. A refresh parses a file again when what it
663
+ invokes changes elsewhere, and equals a cold index.
664
+
665
+ ### Measured
666
+
667
+ The maintainer ran this release on the private dogfood set on 2026-10-14 (ADR 0003).
668
+
669
+ Links. One consumer repository calls the provider from four sites in its current code (ADR 0003
670
+ counted five); all four link to the right route at `inferred`, through `base_url_env`. The other
671
+ consumer repository's three calls do not link: its client receives `fetch` as a parameter and
672
+ takes the URL from a destructured object, two patterns this release does not read (#157, #158).
673
+
674
+ Cost, on the provider repository at the 2026-10-11 commit nearest to 633 files (634 TypeScript
675
+ and JavaScript files), median of three runs on a 16-thread Linux laptop:
676
+
677
+ | Metric | Target | Result |
678
+ | --- | --- | --- |
679
+ | Cold index time | ≤ 7 s | 1.2 s |
680
+ | Cold index size | ≤ 37 MB | 21.8 MB |
681
+ | Single-file reindex | ≤ 1 s | 0.24 s |
682
+ | Tool list | ≤ 1k tokens | 454 tokens |
683
+ | Default answer | ≤ 2k tokens | 1,834 tokens, the largest of 11 answers |
684
+
685
+ At today's 664 files: 1.3 s, 23.6 MB and 0.26 s. Tokens count 4 bytes each, as the answer budget
686
+ does. These numbers gate 1.0, not this release.
687
+
688
+ Communities and processes (spec #31) were measured on 2026-10-17 on the same repository, at the
689
+ same commit and at that day's 692 files. The runs used release builds of `main` just before and
690
+ just after the spec, each a median of three runs on a 16-thread Linux laptop with 7.2 GiB of
691
+ RAM. MB here means 10^6 bytes.
692
+
693
+ | Metric | Target | 634 files, before → after | 692 files, before → after |
694
+ | --- | --- | --- | --- |
695
+ | Cold index time | ≤ 7 s | 1.81 s → 1.80 s | 2.20 s → 2.12 s |
696
+ | Cold index size | ≤ 37 MB | 22.7 MB → 23.0 MB | 26.8 MB → 27.1 MB |
697
+ | Single-file reindex | ≤ 1 s | 0.74 s → 0.76 s | 0.89 s → 0.92 s |
698
+ | Tool list | ≤ 1k tokens | | 620 tokens |
699
+ | Default answer | ≤ 2k tokens | | 1,996 tokens, the largest of 11 answers |
700
+
701
+ The tool list counts the whole `tools/list` result as compact JSON. Among the 11 answers are
702
+ `context` on the three most-called symbols, each with its community and process membership,
703
+ and `trace` from the two longest processes. The spec adds about 0.3 MB and 0.03 s to a reindex.
704
+ The rise of the single-file reindex since 2026-10-14 predates it (specs #22 and #23), and at
705
+ 692 files it is close to its target.
706
+
707
+ [Unreleased]: https://github.com/ClaudioMascaro/meada/compare/v1.0.0...HEAD
708
+ [1.0.0]: https://github.com/ClaudioMascaro/meada/releases/tag/v1.0.0
709
+ [0.1.0]: https://github.com/ClaudioMascaro/meada/releases/tag/v0.1.0