@meada/meada 1.0.0 → 1.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/CHANGELOG.md CHANGED
@@ -6,6 +6,382 @@ All notable changes to Meada are recorded here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.1.0] - 2026-11-02
10
+
11
+ A minor release on the [1.x stability promise](https://github.com/ClaudioMascaro/meada/blob/main/docs/site/en/stability.md):
12
+ local accounts (ADR 0024) in the console, the proposal server and the nodes, carried by the
13
+ `cloud` image, the Compose recipe and the Helm chart; the export's `format` and indexed commit;
14
+ client-side deadlines on every Postgres call; durable pulled-generation writes; resolver fixes
15
+ for C#, Kotlin, Rust and Swift (tier b3); and the fixes of tiers b1 and b2. The index schema
16
+ version changes, so existing indexes are rebuilt once on first use. `meada-core` 1.1.0 adds `format`, `commit` and `dirty` to `Export`, and its
17
+ `export::parse` refuses a document without `format`: re-export with 1.1.0 before parsing an export
18
+ written by 1.0.0. The tree, the `meada-core` pin, the Dockerfile, the compose defaults and the
19
+ Helm chart declare `1.1.0`, and the `v1.1.0` tag follows this entry's merge on main. Publication
20
+ (crates, the staged npm package, the GitHub draft release) belongs to the maintainer.
21
+ Release notes are available in
22
+ [pt-BR](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.1.0.md),
23
+ [English](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.1.0.en.md) and
24
+ [Spanish](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.1.0.es.md).
25
+
26
+ ### Added
27
+
28
+ - The export format and the indexed commit (#512, ADR 0004 "Canonical export"): every export
29
+ starts with `format` (`meada_core::export::FORMAT`, 1), which rises only when a reader of the
30
+ previous shape would misread the new one, never for an added optional field; then
31
+ `repository`, then `commit` and `dirty`, both optional and left out together. Locally `meada export` reads `HEAD` before and
32
+ after its refresh and the checkout's status after it (ignored files, `.meada/` among them, do
33
+ not count), and names the commit only when `HEAD` did not move and the index is fresh; outside
34
+ git or before the first commit both are left out. In server mode they come from the commit
35
+ `meada index --workspace` recorded beside the index, or a generation's `head`, never from the
36
+ mirror's live `HEAD`, with `dirty` false. For `meada-core` crate users: `Export` gains
37
+ `format`, `commit` and `dirty` (a minor change, the struct being `#[non_exhaustive]`, so the
38
+ next `meada-core` release is 1.1.0), and `export::parse` refuses a document without `format`,
39
+ naming the field, so an export written before this release no longer parses. Every `*.export.json` golden gained the three fields.
40
+
41
+ - Named workspaces and the proposal server with local accounts (#562, ADR 0024, from #551):
42
+ `[catalog]` and `[workspaces]` (and so `[proposals]`) accept `[accounts.github]` in place of
43
+ `[oidc.github]` and still need one of the two (`[catalog] needs [oidc.github] or
44
+ [accounts.github]`; `[workspaces]` now names `[ui]` and `[catalog]`, the catalog naming the
45
+ provider). Eligibility reads the account's verified login, an operator account is the platform
46
+ administrator, and workspace operator lists, version authors, history and audit records name
47
+ `local:` subjects. `POST /api/v1/account/tokens` takes `{"surface": "proposals"}` when the
48
+ console's bootstrap has `[proposals]` (audience `meada:proposals`; a 422 `invalid_surface`
49
+ without it), `config` carries `"proposals": true` and the profile page offers the surface. The
50
+ proposal server with `[accounts]` and no `[oidc]` reads the public key at start and admits only
51
+ those tokens (a session token or a node's agent token is a 401 with `WWW-Authenticate: Bearer`,
52
+ no protected resource metadata), deriving the subject, login, groups, grant and role from the
53
+ token alone. No golden changed.
54
+ - The verified GitHub login of local accounts (#561, ADR 0024, from #551): `[accounts.github]`
55
+ (`host`, `roles`, `max_age_seconds` as `[oidc.github]`, plus `api`, `https://api.github.com` by
56
+ default on `github.com` and required on any other host) is the GitHub grant provider of local
57
+ accounts. A person pastes a GitHub personal access token on their profile page or sends it to
58
+ `POST /api/v1/account/github`; the console calls `GET /user` on `api` once, keeps the lowercase
59
+ login and drops the token, and answers a fresh session token carrying the login. A login
60
+ another account holds is a 409 `login_taken`, GitHub's refusal a 422, GitHub out of reach a
61
+ 503. `POST /api/v1/account/github/remove` and the accounts page's `remove_github` action remove
62
+ it. Session and agent tokens carry the verified login, so the GitHub grant joins the groups
63
+ grant in the console (`session` shows `login`, `github_host` and `github_grant`), on nodes, in
64
+ a team operator's additions (`added_by`), in the audit's `login` column and in the exclusions
65
+ marks; `meada github-app roles` reads `[accounts.github]`. Recorded `account.github` and
66
+ `account.remove_github`; the personal access token is never stored, logged or audited. No
67
+ golden changed.
68
+
69
+ - Helm chart support for local accounts (#565, ADR 0024, from #551): `modules.accounts` renders
70
+ `[accounts]` from values, with `values-accounts.yaml` as the proof-of-concept shape (a writable
71
+ console with `operations = true`, Postgres and no identity provider). The Ed25519 private key
72
+ comes from its own Secret and is mounted only in the console's `console` container, the public
73
+ key from another Secret in the console and the nodes (a node also gets `[ui] public_url`, the
74
+ token issuer, and `[postgres]`), the initial admin password from an optional Secret in the
75
+ console. `modules.accounts.groups` and `modules.accounts.github` carry `[accounts.groups]` and
76
+ `[accounts.github]` (the refresh job, with `modules.githubApp`, gets the GitHub grant provider and runs the role check, and
77
+ `modules.workspaces` accepts it in place of `modules.oidc.github`); `modules.accounts.breakGlass`
78
+ keeps `[accounts]` in the console alone beside `modules.oidc`. The chart refuses a missing
79
+ Postgres or console, equal key Secrets, accounts beside OIDC without break glass, and groups or
80
+ GitHub under break glass. `scripts/helm-check` covers the sections, the mounts and the refusals;
81
+ the chart READMEs (pt-BR, English, Spanish) no longer say a writable console needs OIDC. The
82
+ proposal server is not part of the chart. `[accounts.github]` renders as the spec names it and
83
+ is parsed once #561 lands. No golden changed.
84
+
85
+ - One-command proof of concept in the Compose recipe (#564, ADR 0024, from #551):
86
+ `cp .env.accounts.example .env && docker compose up -d` starts the generations fleet, Valkey,
87
+ the store, Postgres with its migration, a writable console with local accounts and nodes that
88
+ admit agent tokens. `compose.accounts.yaml` adds the Ed25519 key pair (made once by the
89
+ `certificates` step, never printed, the private key mounted read-only in the console alone and
90
+ the public one in the nodes), the console's and the nodes' `[accounts]` manifests, a one-shot
91
+ `seed` of the first workspace version (only while the store has none) and a node proxy that
92
+ forwards `Authorization` with no static bearer. The other profiles are unchanged, and
93
+ `scripts/compose-check` covers the new one. The Compose README (pt, en, es) starts with it and
94
+ covers `MEADA_ADMIN_PASSWORD`, `meada ui reset-admin`, key rotation and rate limiting the
95
+ sign-in route at the proxy.
96
+
97
+ - Agent tokens for the nodes (#560, ADR 0024, from #551): a signed-in local account generates,
98
+ on its profile page or through `POST /api/v1/account/tokens` (`{surface: "nodes", hours}`, 1 to
99
+ 168 hours, 8 by default), an agent token shown once (`{token, expires_at, surface}`), signed
100
+ with the account's role and groups as its row stands and a random token id, recorded
101
+ `account.token` (surface, hours, token id, never the token). A change-required account gets the
102
+ 403 `password_change_required`, a suspended one the role refusal; the console answers an agent
103
+ token with 401. A node with `[accounts]` and no `[oidc]` (`meada mcp --listen`) now reads the
104
+ signing public key at start, and the console's `[ui] public_url` from a `[ui]` section its
105
+ manifest must carry, refusing to start without either; it admits only agent tokens for the
106
+ nodes (a 401 `Bearer` before routing for any other, a session token included) and answers
107
+ under the grant `[accounts.groups]` gives their groups (every repository without the table),
108
+ as an identity provider's token is answered. The `accounts` feature now implies `ui`. No golden
109
+ changed.
110
+
111
+ - Accounts page in the console (#559, ADR 0024, from #551): the global operator of a console with
112
+ local accounts gets `/accounts`, listing every account (role, groups, state with a suspended
113
+ account marked and a locked one saying until when, change required, last password change), a
114
+ create form (username pattern and password length checked first, "change on first sign-in"
115
+ checked by default) and, per account, role, groups, suspend, reactivate and reset password,
116
+ each behind the shared confirmation dialog with the server's refusals (`last_operator` and the
117
+ rest) shown unchanged. Any other role, and a console under break glass, gets the not-found
118
+ page at that path. The audit page names every `account.*` action in Portuguese and English.
119
+ The password rule `common_password` now has its own copy. Front end only, no golden changed.
120
+
121
+ - Groups of local accounts (#558, ADR 0024, from #551): the global operator gives accounts groups
122
+ (`groups` on `POST /api/v1/accounts`, and the `groups` action of
123
+ `POST /api/v1/accounts/<username>`, each an owner name, else a 422 `invalid_group`);
124
+ `GET /api/v1/accounts` lists them, and each change is recorded `account.groups`.
125
+ `[accounts.groups]` maps groups to identities as `[oidc.groups]` does: once it exists, a local
126
+ session's grant is what its groups map to, and it bounds every view (the manifest, the
127
+ workspace and its versions, the store, the repositories, the credentials, the playground, the
128
+ exports and the graph views) as an identity provider's grant does; without it every local
129
+ account still reads every repository. A local viewer whose group owns an entry of the current
130
+ workspace version its grant reads is a team operator (ADR 0015). Session tokens carry the
131
+ groups, so a change reaches reads at the next sign-in and writes at once (the account row is
132
+ read before each). `GET /api/v1/admission` with `[accounts]` now answers: `accounts` (the mode,
133
+ `accounts` or `break_glass`, and the signing public key's fingerprint, `blake3:` and the hex
134
+ BLAKE3 hash of the raw Ed25519 key) and, without `[oidc]`, the groups table bounded by the
135
+ caller's grant. No golden changed.
136
+
137
+ - Account administration for local accounts (#557, ADR 0024, from #551): the global operator
138
+ lists every account (`GET /api/v1/accounts`: username, role, state, the end of a lock, change
139
+ required, last password change, created and created by, never a hash), creates one
140
+ (`POST /api/v1/accounts`, `{username, role, password, change_required}`, the policy applied to
141
+ the temporary password, a change required unless the body turns it off; a malformed username a
142
+ 422 `invalid_username`, a taken one a 409 `username_taken`) and changes one
143
+ (`POST /api/v1/accounts/<username>`, one `action`: `role`, `suspend`, `reactivate` or
144
+ `reset_password`, which clears a lock and requires a change unless told not to; an unknown
145
+ account a 404). Suspending or demoting the last active operator is a 409 `last_operator`,
146
+ decided under the schema's advisory lock so two requests at once never leave none. Anyone else
147
+ gets a 403. The routes answer whatever `[ui] operations` says; workspace and generation writes
148
+ keep requiring it. Every console write of a local account now reads the account's row first,
149
+ so a suspended or demoted account loses its writes at once, while its reads last until its
150
+ token expires. Audit actions `account.create`, `account.role`, `account.suspend`,
151
+ `account.reactivate` and `account.reset_password` name the account and the fields changed,
152
+ never a password, written before the change (503 `audit_unavailable` otherwise); `account` is
153
+ the route-level action of a change refused before its body is read. No route deletes or
154
+ renames an account; under `[accounts] break_glass` (#563) none of these routes exists, each a
155
+ 404. No golden changed.
156
+
157
+ - Break-glass account beside the identity provider (#563, ADR 0024, from #551): `[accounts]
158
+ break_glass = true` lets the section sit beside `[oidc]`; without `[oidc]` it is an error, and
159
+ `[accounts.groups]` or `[accounts.github]` under it is an error naming the table. The console
160
+ then signs in only the default account (any other username gets the wrong password's 401,
161
+ audited `not_break_glass`, the table never read) as the global operator, and admits its session
162
+ token beside the identity provider's, each bearer routed by its issuer to one verifier, so the
163
+ identity provider's keys never check a console token and the signing key never checks an
164
+ identity provider's; a console whose `[oidc] issuer` is its own `public_url` refuses to start.
165
+ The password change works; no other route of local accounts exists. Nodes and the proposal
166
+ server keep admitting only the identity provider and read no key. `config` adds `break_glass:
167
+ true`, and the front end offers a discreet break-glass sign-in (`/break-glass`) beside the
168
+ identity provider's, which now waits for a click under break glass. No golden changed.
169
+
170
+ - Hardening of local sign-in (#555, ADR 0024, from #551): the password policy refuses an embedded
171
+ common-password list (SecLists, MIT, the entries of 12 to 128 characters, compared ignoring
172
+ case; rule `common_password`). Ten consecutive failed password checks, at sign-in or as a
173
+ password change's current password, lock an account for fifteen minutes, counted in a
174
+ transaction holding the account row so parallel attempts never pass ten; a success resets the
175
+ count. A locked account gets the wrong password's 401 at a hash's cost, its password unchecked
176
+ and its lock never extended, audited `locked_now` and then `locked`. A stored hash weaker than
177
+ the console's parameters is redone at the next successful sign-in. `meada ui reset-admin
178
+ --workspace <manifest>` (features `ui` and `accounts`) creates or reactivates `admin` as an
179
+ operator, clears its lock and sets the `MEADA_ADMIN_PASSWORD` value or a generated password
180
+ printed once on stdout, with a change required, recorded `account.reset_admin` `via` `cli`
181
+ before the write and refusing with exit 1 when the record cannot be written. No golden changed.
182
+
183
+ - Local sign-in for the console (#554, ADR 0024, from #551): the new `accounts` cargo feature
184
+ (enabled by `cloud`) and its `[accounts]` section, which needs `[postgres]` and never sits
185
+ beside `[oidc]`, name the Ed25519 signing key pair and the default account's initial password,
186
+ each from a variable or a file. Migration 9 adds the `accounts` table, so `meada postgres
187
+ migrate` reaches version 9. On its start the console checks the key pair and creates the
188
+ default account `admin` (password `admin123` with a change required, or the policy-checked
189
+ `MEADA_ADMIN_PASSWORD` without) once, under an advisory lock. `POST /api/v1/login` answers a
190
+ session token the console signs with EdDSA for eight hours; a token carrying the change-required
191
+ mark opens only `POST /api/v1/account/password`. Every route but the static files, `config` and
192
+ `login` then needs a session token; `[ui] operations = true` is accepted with `[accounts]` and
193
+ no `[oidc]`; `config` names the sign-in mode (`sign_in`: `accounts`, or `oidc` with an identity
194
+ provider), `session` adds `account: true`, and
195
+ every account reads every repository while no groups table bounds it. Passwords are argon2id at
196
+ OWASP's parameters under a policy of 12 to 128 characters that refuses the default password and
197
+ the username, at most four hashes run at once, and every sign-in, refusal and password change
198
+ is audited (`account.login`, `account.password`, role `none` for an unknown username) before its
199
+ token. The module table gains `accounts`; no golden changed.
200
+
201
+ - The console's sign-in pages for local accounts (#556, from #551): when `config` says
202
+ `"sign_in": "accounts"` the console shows its own sign-in page (labelled username and password,
203
+ one generic refusal, `busy` and `audit_unavailable` shown as themselves) instead of the identity
204
+ provider's redirect. A change-required sign-in goes straight to a forced password change page
205
+ (the current password and the new one twice, the server's rule shown on a refusal) that offers
206
+ nothing to navigate to until it succeeds, and then opens the workspace. The session token lives
207
+ in `sessionStorage` for the tab's life, is sent as the bearer and is cleared on sign-out and on
208
+ any 401 (which returns to sign-in; a refused current password in the change is not one); it is never in `localStorage`, a URL
209
+ or a log. A profile page offers the voluntary password change and sign-out. pt-BR and English
210
+ copy; the identity provider flow is unchanged. Front end only: no golden changed.
211
+
212
+ - `meada status` names a Kotlin file the grammar misreads (#546, from #434). A declaration read
213
+ as an infix call leaves the file out of the index; the file now sets the new `Facts::misparsed`
214
+ (absent from every other file's stored facts) instead of `unbuilt`, and a new status line,
215
+ `Msg::FileMisparsed`, in English and Portuguese, names it beside the byte-budget and using
216
+ drops. The Java and Kotlin layout skips it as it skips the other drops. The schema version is
217
+ the same: a file dropped before the upgrade gets its line when it next changes, or at once
218
+ after deleting `.meada/index.db`. The `cli.status-budget` goldens gained the new line.
219
+
220
+ ### Changed
221
+
222
+ - The grant providers take neutral inputs (#553, from #551): the new `grant` module computes a
223
+ subject's grant from its groups and its GitHub login (`Providers::grant`), with no reference
224
+ to a token, and holds the GitHub grant provider's permissions cache, which moved out of the
225
+ OIDC module; the OIDC module feeds it from a token's claims. Every reader of `[oidc.github]`
226
+ goes through `Manifest::github`, the console and the proposal server build their sessions
227
+ from a neutral admitted subject (`grant::Admitted`), and a node's pass carries only a grant.
228
+ Nothing a caller sees changes; no golden changed.
229
+
230
+ - The axum provider reader walks each value once per file (#431): the values a file's rebound
231
+ `let`s reach share one `seen` set, and `Code::origins` is not asked for a call whose builder
232
+ chain goes through a method no router hands back, nor for a name written as text, a path, a
233
+ number, a boolean or a character. The reader's share of a one-file refresh on this repository
234
+ drops from about 1.4 s to about 0.1 s. No golden changed.
235
+
236
+ ### Fixed
237
+
238
+ - Swift: a call whose labels differ from a known outside member's resolves as if that base
239
+ were absent (#463): `x.hash(seed: 1)` on a type that conforms to `Hashable` and declares
240
+ `hash(seed:)` is `exact`, while `x.hash(into: &h)` stays opaque. A call with no labels, or in
241
+ another language, is still compared by its bare name.
242
+ - Swift: an alias of an outside type reaches the repository's extensions of that type (#440). A
243
+ receiver typed by `typealias Anim = Animation`, or by an alias of an alias, and `Anim.build()`
244
+ match `extension Animation { }` as `Animation` does; an alias of an outside type with no
245
+ extension stays unresolved.
246
+ - Rust: a call after `?` or `.await` is typed by the value they unwrap (#435, after #401): the
247
+ pack keeps beside a function's written result the first type argument of a `Result` or
248
+ `Option` (`Def::unwrapped`) and the `Output = T` of `impl Future<Output = T>` and
249
+ `Pin<Box<dyn Future<Output = T>>>` (`Def::output`, read only through `.await`), so
250
+ `load()?.port()` and `fut().await.port()` resolve within `T`'s family, `exact` when it
251
+ declares one `port`, where `?` left a name match and a plain `fn` returning a future resolved
252
+ to nothing. A type outside the repository, or a `?` before an `.await`, leaves the call as
253
+ it was. The stored facts gain
254
+ `Def::unwrapped`, `Def::output`, `Call::unwraps` and `Call::awaits`, so the schema version
255
+ changes and Rust indexes are rebuilt once.
256
+ - Kotlin: a class, object or interface nested in an `expect` declaration, at any depth, is
257
+ `expect` too (#437), so a use of it resolves to the `expect` one instead of staying
258
+ `ambiguous` among its `actual` declarations.
259
+ - C# `using static T` imports only the static members and nested types `T` declares (#433): a bare
260
+ `Go()` with `Go` on a base of `T` was an `exact` link to the base's method, which C# rejects
261
+ ("inherited members aren't imported"), and is now a name match at best; `using static` of the
262
+ base itself still gives it. Java's `import static` and Kotlin keep reading inherited members.
263
+ - Kotlin: a bare call resolves in Kotlin's order, an extension of the implicit receiver in scope
264
+ before a top-level function of its name (#436, from #402): inside `fun CoroutineScope.x() {
265
+ launch { } }` the call is `exact` to `CoroutineScope.launch`, not to the top-level `launch`
266
+ (`ambiguous` with it when the extension may apply to any receiver), and an `object`'s name is
267
+ its instance, so `Dispatchers.setMain(..)` reaches an imported `fun Dispatchers.setMain` (it
268
+ was no link) while a class's name keeps companion and statics. "Known ceilings" drops the
269
+ bare-call line. No golden changed.
270
+ - C#: an `internal`, `private` or `private protected` constructor or method of a public type is
271
+ a candidate from its own project's files alone (#441); `InternalsVisibleTo` stays unread.
272
+ - The console writes one `ui: directory: unreadable` stderr line per request when the directory
273
+ cannot be read (#451, after #335): the request's session remembers the failure at admission,
274
+ so the flags, the admission counts and the owner picker take that answer and write no second
275
+ line (`workspace` wrote two), and a write it refuses as 503 `audit_unavailable` prints no
276
+ pre-authentication audit line beside it. Reads still answer with the flags unavailable, the
277
+ counts null and the picker a 503; writes still refuse as before. No golden changed.
278
+ - Postgres calls that had no client-side deadline now have one (#447): a SCIM request (under the
279
+ directory's one write lock), the role check's fence read and write transaction, and the
280
+ console's start check, so a Postgres that accepts the connection and stops answering ends in a
281
+ 503, an exit 1 with no exclusions file a reader admits, and a console that starts, instead of
282
+ holding them forever. `postgres::Config::bound(n)` now adds the version check's two statements
283
+ itself and every call site counts only its own (the audit and directory reads and the overage
284
+ lookup moved accordingly; the accounts' calls, which undercounted, and the permissions poll
285
+ gained the two). No golden changed.
286
+ - A crash after the pointer swap can no longer leave `current` naming a version document that
287
+ never reached the disk (#518): the pointer, the version document `meada workspace pull` writes,
288
+ the pulled contexts file and the exclusions file are replaced through one helper
289
+ (`pull::replace`) that syncs the new file before the rename and removes `<name>.new` when a
290
+ step fails. A failed pointer rename now names `current`, not `current.new`.
291
+ - The docs say what 1.0.0 ships: nine languages (TypeScript, JavaScript, Python, Go, Rust, Java,
292
+ Kotlin, C# and Swift). The three READMEs, the three 1.0.0 release notes and the three user
293
+ guides no longer call Java, Kotlin, C# and Swift later 1.x work, the user guides gain a section
294
+ for each of the four (9.5 to 9.8) with their brokers (JMS, Azure Service Bus) and package
295
+ ecosystems (Maven and Gradle, NuGet, SwiftPM), and ADR 0003 records the change in an
296
+ amendment. No code, default dependency or golden changed.
297
+ - A server-mode mirror's `meada.toml` and `meada.decisions.toml` are read through no symbolic
298
+ link (#547, after #506), as a pulled generation's are: `mirror()`, behind `Manifest::read`
299
+ (`mcp --listen`, snapshot pull, the lock and pointer operations, workspace versions, the
300
+ heartbeat, the UI, the workspaces CLI, the GitHub App), now refuses a link unopened, one that
301
+ stays inside the mirror included, a file that is not regular and a file replaced while read,
302
+ with the generation's messages, and bounds each file at 1 MiB (`GENERATION_CONFIG_MAX`, now
303
+ built without the `snapshot` feature). A local checkout and an operator's own files still
304
+ follow links. The architecture map and the snapshots page, in its three languages, say so.
305
+ - No manifest error quotes a written value (#545), after #449 stopped serde's `invalid type` and
306
+ `invalid value`: `unknown variant` names the key and the values it accepts (`` `workspace.source`:
307
+ is not one of the values it accepts (`file`, `store`) ``) instead of serde's text, an error no
308
+ key spans reads "a value is not valid here" instead of serde's message, and the rule errors
309
+ for `serve.prefix`, `serve.strip`, `serve.documents` and a resource's `kind` name the key and
310
+ the rule (`` `serve.strip`: must start with `/` ``) instead of the value. The console's cut of
311
+ an error to its position stays as a second guard (it still covers an error built outside
312
+ `describe` that names an identity). English and pt-BR texts changed; the workspace validation
313
+ fixture changed only by the new texts.
314
+ - The deploy fetch reads a `[[repository]]` entry by its own keys (#544): any table header ends
315
+ the entry before it, so a `[[repository.peer]]` or `[[repository.resource]]` table no longer
316
+ replaces its `repo` or `path`, and a value is the text between its quotes, so a trailing
317
+ comment is not part of it. Before, such a version stopped the Compose refresh and let the chart
318
+ clone the peer's repository into the entry's path (or into a directory named after the
319
+ comment). `fetch-pulled.sh` and the chart's `workspace.fetch` carry one awk program, and a
320
+ test fails when the two copies drift. No golden changed.
321
+ - A repository identity on the `[oidc.github]` host compares without case wherever it meets the
322
+ catalog (#508): the roles job gives a selected `github.com/Acme/API` and the catalog's
323
+ `github.com/acme/api` one `both` row keyed as written, the `max_repositories` cap does not
324
+ count it as extra, and the console's catalog check and listing match it. A repository selected
325
+ in two spellings (a deployment's `github.com/Acme/API`, a named workspace's
326
+ `github.com/acme/api`) keeps one `source` row under the first and gets its role rows under
327
+ each, so grants, which match exactly, read both. Other hosts compare exactly. No golden
328
+ changed.
329
+ - Compose mirror origins (#445): `fetch.sh` and `fetch-pulled.sh` read an existing mirror's
330
+ `origin` before fetching and refuse one whose HTTP(S) URL carries credentials (a mirror cloned
331
+ from a URL with a token keeps it there), naming the identity and never the URL, and the refresh
332
+ stops before index and publish as a failed fetch does. The READMEs tell the operator to run
333
+ `git remote set-url origin <URL without credentials>` in such a mirror.
334
+ - Java and Kotlin: a file with thousands of fields and locals is read in linear time (#442, from
335
+ #424). The hides check indexes the fields by name instead of scanning every field per local,
336
+ the class around a write is found from the prefixes of its scope, and `declared_before` (and
337
+ Kotlin's `assigned`) read a node's parent from an index built once per file, since
338
+ `Node::parent()` is found from the root and made a deep file quadratic per write. Same answers;
339
+ no golden changed.
340
+ - Indexing: a file a pack drops for passing a limit is named by `meada status` (#434, from
341
+ #419). The Java, Kotlin and Swift qualified-name budget (4 MiB) now sets `Facts::budget`, as the
342
+ C# one does, instead of `unbuilt`, which prints nothing; a C# project that gives its files more
343
+ than 256 usings (`PROJECT_USINGS`) marks each of them with the new `Facts::usings`, which a new
344
+ status line names (`Msg::FileTooManyUsings`, with the count). Kotlin's `misparsed` file stayed
345
+ `unbuilt` (a grammar defect, not a limit; #546 names it too). An index built before this change keeps a Java,
346
+ Kotlin or Swift file dropped by its budget as `unbuilt` until the file changes. No limit
347
+ changed. The `cli.status-budget` goldens gained the new cases; no stored format golden changed
348
+ (the new field is absent from every sample), so the schema version is the same.
349
+ - Resolution: the receiver and call depth (`RECEIVER_DEPTH`) is one count for the whole lookup
350
+ (#432, from #417), carried through a glob, an alias or an on-demand import as the link count is,
351
+ so a chain that alternates receivers and imports costs its length, not `RECEIVER_DEPTH` per link
352
+ up to `LINK_DEPTH`. No limit changed and no answer under the limits; no golden changed.
353
+ - Helm: the default `workspace.fetch` (#444, from #316) reads the repositories from `$1` when
354
+ given (the pulled list under `modules.oidc.github`) else from `workspace.repositories`, now
355
+ mounted as `repositories.toml` so a store-sourced refresh, whose bootstrap lists none, still
356
+ fetches the operator's list, refuses a URL carrying a credential and, as the compose
357
+ scripts do (#445), an existing mirror whose `origin` carries one, keeps each mirror strictly
358
+ under `/data/mirrors`, and on failure prints `refresh: fetch failed for <identity>; the refresh
359
+ stops before publication` and exits nonzero without echoing a URL or token.
360
+ `scripts/helm-check` runs the rendered script under `sh` with a stub `git` to check these; the
361
+ chart READMEs describe it.
362
+ - Workspace import (#450): `meada workspace import` reads its file once, bounded by the version
363
+ size limit, and audits the id of the text it stored; a file past the bound or not a regular
364
+ file is refused before any audit record is written.
365
+ - Manifest type errors (#449): a `meada.toml` or workspace manifest key of the wrong type, or
366
+ with an invalid value, reports the key and the expected kind (`` `oidc.entra`: has the wrong
367
+ type (a table was expected) ``) instead of serde's message, which echoed the written value, so a
368
+ secret pasted under the wrong key no longer reaches stderr.
369
+ - Pulled generations (#506): a mirror's `meada.toml` or `meada.decisions.toml` that is a symbolic
370
+ link is refused unopened, the error naming the file, so a repository can no longer make a node
371
+ read and parse a file of the host. A link into the mirror (`meada.toml -> conf/meada.toml`) is
372
+ refused too, as the index refuses a linked pack config. The file opened is checked to be the one
373
+ checked. Secrets and CAs a manifest names still follow links (Kubernetes mounts them through
374
+ one). The snapshots page says so in its three languages.
375
+ - Named workspaces on a node (#510): a node shows a named workspace's route
376
+ (`/-/workspaces/<id>/<identity>`, pinned or not) and lists it in a 404 only to a token whose
377
+ grant reads every entry of the workspace's version, the entries the sponsor rule excluded
378
+ included, as the console does. Before, once A of a Y+A workspace lost its sponsor, a subject
379
+ reading Y alone found the workspace on a node. A generation's context now records `excluded`,
380
+ the identities the sponsor rule left out, sorted, and its digest covers them; a context without
381
+ one is written as before, with the same generation id, and a generation published earlier reads
382
+ as none excluded. A node on an older binary refuses a generation that records an exclusion, so
383
+ upgrade nodes before or with the publisher. No golden changed.
384
+
9
385
  ## [1.0.0] - 2026-10-30
10
386
 
11
387
  The tree declares `1.0.0`: this release raises the workspace, the `meada-core` pin, the Dockerfile,
@@ -704,6 +1080,7 @@ and `trace` from the two longest processes. The spec adds about 0.3 MB and 0.03
704
1080
  The rise of the single-file reindex since 2026-10-14 predates it (specs #22 and #23), and at
705
1081
  692 files it is close to its target.
706
1082
 
707
- [Unreleased]: https://github.com/ClaudioMascaro/meada/compare/v1.0.0...HEAD
1083
+ [Unreleased]: https://github.com/ClaudioMascaro/meada/compare/v1.1.0...HEAD
1084
+ [1.1.0]: https://github.com/ClaudioMascaro/meada/releases/tag/v1.1.0
708
1085
  [1.0.0]: https://github.com/ClaudioMascaro/meada/releases/tag/v1.0.0
709
1086
  [0.1.0]: https://github.com/ClaudioMascaro/meada/releases/tag/v0.1.0
package/README.md CHANGED
@@ -18,7 +18,7 @@ Escolha a linha que combina com o que você já tem. Todos os canais entregam o
18
18
  | Rust | `cargo install meada` | `meada mcp` |
19
19
  | Linux ou macOS | o instalador de shell abaixo | `meada mcp` |
20
20
  | Qualquer sistema | o arquivo do seu sistema nas [releases do GitHub](https://github.com/ClaudioMascaro/meada/releases), com `meada` no `PATH` | `meada mcp` |
21
- | Docker | `docker pull ghcr.io/claudiomascaro/meada:1.0.0` | a linha `docker run` em [Conectar um agente](#conectar-um-agente-mcp) |
21
+ | Docker | `docker pull ghcr.io/claudiomascaro/meada:1.1.0` | a linha `docker run` em [Conectar um agente](#conectar-um-agente-mcp) |
22
22
 
23
23
  ```sh
24
24
  # Instalador de shell (Linux e macOS)
@@ -75,7 +75,7 @@ Com Docker (Linux e macOS):
75
75
  "mcpServers": {
76
76
  "meada": {
77
77
  "command": "sh",
78
- "args": ["-c", "exec docker run -i --rm --network none --user \"$(id -u):$(id -g)\" -v \"${PWD%/*}:${PWD%/*}\" -w \"$PWD\" ghcr.io/claudiomascaro/meada:1.0.0 mcp"]
78
+ "args": ["-c", "exec docker run -i --rm --network none --user \"$(id -u):$(id -g)\" -v \"${PWD%/*}:${PWD%/*}\" -w \"$PWD\" ghcr.io/claudiomascaro/meada:1.1.0 mcp"]
79
79
  }
80
80
  }
81
81
  }
@@ -97,7 +97,7 @@ ler os níveis de uma resposta. No Claude Code:
97
97
 
98
98
  ```sh
99
99
  mkdir -p ~/.claude/skills/meada
100
- curl -fsSL https://raw.githubusercontent.com/ClaudioMascaro/meada/v1.0.0/skills/meada/SKILL.md -o ~/.claude/skills/meada/SKILL.md
100
+ curl -fsSL https://raw.githubusercontent.com/ClaudioMascaro/meada/v1.1.0/skills/meada/SKILL.md -o ~/.claude/skills/meada/SKILL.md
101
101
  ```
102
102
 
103
103
  Outros agentes: veja [Agentes e MCP](https://claudiomascaro.github.io/meada/mcp/#skill-para-agentes).
@@ -111,8 +111,8 @@ Meada 1.0 entrega todo o escopo da v1 do [ADR 0003](docs/adr/0003-v1-scope-and-r
111
111
  - **Níveis**: um nível em cada ligação, cadeias que atravessam repositórios e decisões com
112
112
  decisor opcional (`meada decide`).
113
113
  - **Análises**: drift de forma, comunidades e processos.
114
- - **Linguagens no 1.0**: TypeScript e JavaScript, Python, Go e Rust. Java, Kotlin, C# e Swift
115
- são trabalho planejado da Release 2 e chegam depois como versões 1.x (#26 a #29, ADR 0003).
114
+ - **Linguagens no 1.0**: nove, TypeScript, JavaScript, Python, Go, Rust, Java, Kotlin, C# e
115
+ Swift (#26 a #29, ADR 0003).
116
116
 
117
117
  **Promessa de estabilidade.** A partir do 1.0 vale o semver: uma mudança incompatível em um
118
118
  destes itens pede uma versão major.
@@ -19,7 +19,7 @@
19
19
  "hasInstallScript": true,
20
20
  "license": "Apache-2.0",
21
21
  "name": "@meada/meada",
22
- "version": "1.0.0"
22
+ "version": "1.1.0"
23
23
  },
24
24
  "node_modules/detect-libc": {
25
25
  "engines": {
@@ -48,5 +48,5 @@
48
48
  }
49
49
  },
50
50
  "requires": true,
51
- "version": "1.0.0"
51
+ "version": "1.1.0"
52
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "artifactDownloadUrls": [
3
- "https://github.com/ClaudioMascaro/meada/releases/download/v1.0.0"
3
+ "https://github.com/ClaudioMascaro/meada/releases/download/v1.1.0"
4
4
  ],
5
5
  "bin": {
6
6
  "meada": "run-meada.js"
@@ -89,7 +89,7 @@
89
89
  "zipExt": ".tar.xz"
90
90
  }
91
91
  },
92
- "version": "1.0.0",
92
+ "version": "1.1.0",
93
93
  "volta": {
94
94
  "node": "18.14.1",
95
95
  "npm": "9.5.0"