@voltro/plugin-audit 0.39.0 → 0.39.1
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 +52 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -39,6 +39,58 @@ _Changes staged for the next release accumulate here (rolled up from
|
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
+
## [0.39.1] — 2026-08-16
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- **@voltro/runtime, @voltro/cli** — An app-registered tuple source is no longer replaced by the framework default.
|
|
47
|
+
|
|
48
|
+
Both boot paths carried this comment, verbatim:
|
|
49
|
+
|
|
50
|
+
> An app whose relationships live in its own tables overrides with > `setTupleSource`.
|
|
51
|
+
|
|
52
|
+
and then called `setTupleSource(default)` **unconditionally**. That call runs AFTER the app's startups — `runBootLifecycle` at `dev.ts:3910` and `serveCommand.ts:869`, against the registration at `dev.ts:4065` and `serveApi.ts:937` — and `setTupleSource` is last-write-wins. So the framework won every time: an app registering its own source in a `*.startup.tsx`, which is what the docs tell it to do, had it silently replaced.
|
|
53
|
+
|
|
54
|
+
The consequence is not subtle. Every relationship guard would then be answered from `_voltro_rebac_tuples` — empty, for exactly the app that keeps its relations in its own tables — so every guard DENIES, fail-closed, with a `no tuple source` warning that never fires because a source *is* registered: the wrong one.
|
|
55
|
+
|
|
56
|
+
The comment was not wrong about the design; it described the design while the code removed it. Same shape as the `DORMANCY_WAKEUP_TENANT` scar — equal by value at both call sites, so nothing could fail, and the comment was the only place the intent survived.
|
|
57
|
+
|
|
58
|
+
`registerDefaultTupleSource` fills the gap only when nobody else did, and returns whether it acted so the boot can say which source is live instead of leaving an operator to guess. `setTupleSource` itself is unchanged: an app calling it twice still gets the second one, because narrowing that would trade one silent surprise for another.
|
|
59
|
+
|
|
60
|
+
Found while re-checking a consumer's claim that a different item was still open. It was not — but it sits beside this, and this is the one that would have bitten them. Pinned in both directions: a unit test for the registrar, and a source guard asserting neither boot path installs `loadResourceTuples` through `setTupleSource` again. Red-verified by restoring the original line.
|
|
61
|
+
- **@voltro/cli** — `voltro doctor` no longer reports "scope vocabulary: none found" when it could not read the config at all.
|
|
62
|
+
|
|
63
|
+
A consumer HAD configured `doctor.scopeVocabulary` and still read `none found`. The cause was not their vocabulary: `app.config.ts` could not be imported outside their pod — an auth strategy demands its secret while the config is evaluated — so the vocabulary was never read. Inside the pod the message disappears and the rule runs.
|
|
64
|
+
|
|
65
|
+
"You have no vocabulary" and "I could not look" are different states, and only the first is a statement about their app. This section already made exactly that distinction one member earlier — its own comment reads **DORMANT AND CLEAN MUST NOT PRINT THE SAME** — and then collapsed the third.
|
|
66
|
+
|
|
67
|
+
The signal existed and was not connected. `offlineManifest` deliberately survives an unimportable config (a doctor run must not die on one), so the empty vocabulary arrived looking like a real absence, while the same failure was reported a hundred lines earlier under plugin tables. The consumer read the section about scopes and searched at the wrong end — which is the correct way to read a report.
|
|
68
|
+
|
|
69
|
+
The rule now probes importability before claiming an absence, and says so:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
• scope vocabulary: NOT EVALUATED — `app.config.ts` could not be imported.
|
|
73
|
+
This is not a statement about your scopes: the rule never got to read them.
|
|
74
|
+
… The same import failure is reported above for plugin tables; both sections
|
|
75
|
+
have this one cause.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The dormant case keeps its own wording, so a quiet run on an app that genuinely publishes no vocabulary is not relabelled as a broken config.
|
|
79
|
+
|
|
80
|
+
### Internal (no consumer-facing effect)
|
|
81
|
+
|
|
82
|
+
- **@voltro/cache, @voltro/kv** — The RESP TTL tests in `@voltro/cache` and `@voltro/kv` stopped measuring the machine. Test-only; no product code changed.
|
|
83
|
+
|
|
84
|
+
Both wrote a key with `ttlMs: 150`, asserted it was still there, then slept 300 ms and asserted it was gone. The second half is fine — waiting LONGER only strengthens "it expired". The first half was a race: the write and the read are two round-trips, so on a loaded runner the key legitimately expired before the liveness assertion, and the test reported a defect that was not there. It failed exactly that way on a release gate, in the keydb engine, while passing locally with 24/24 green.
|
|
85
|
+
|
|
86
|
+
Now: a 2 s window, so liveness has real headroom rather than 150 ms of it, and the expiry is awaited as a CONDITION (`awaitGone` polls) rather than as a duration. Idle machines finish in about the TTL; loaded ones take as long as they need; a key that never expires still fails, because the ceiling is a failure mode and not a timing assumption.
|
|
87
|
+
|
|
88
|
+
Fixed in BOTH packages in one change. The two files carried the identical construction, and this repo's standing lesson is that a fix landing in one copy of a duplicated shape leaves the other one broken — `@voltro/kv` had not failed yet, which is a statement about luck rather than about the test.
|
|
89
|
+
|
|
90
|
+
`@voltro/kv`'s header also pointed at `../cache/test/docker-compose.yml` for bringing the engines up. That path does not exist; there is one compose file, at the repo root.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
42
94
|
## [0.39.0] — 2026-08-16
|
|
43
95
|
|
|
44
96
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/plugin-audit",
|
|
3
|
-
"version": "0.39.
|
|
3
|
+
"version": "0.39.1",
|
|
4
4
|
"description": "Audit plugin — ships the `audit()` schema mixin (createdAt/updatedAt/createdBy/updatedBy → Actor) plus an optional mutation interceptor that records every call to a configurable sink (console / memory / custom function).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"node": ">=24.0.0"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@voltro/database": "0.39.
|
|
42
|
-
"@voltro/logger": "0.39.
|
|
43
|
-
"@voltro/protocol": "0.39.
|
|
41
|
+
"@voltro/database": "0.39.1",
|
|
42
|
+
"@voltro/logger": "0.39.1",
|
|
43
|
+
"@voltro/protocol": "0.39.1"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"effect": "^3.22.0"
|