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