Skip to content

Commit 6548118

Browse files
hotlongclaude
andauthored
test(core, runtime): the retracted verb survived in two case titles — sweep it repo-wide instead of reading one file (#17769)
Follow-up to #17753, found by a post-merge sweep rather than by the pin that PR added. ⛔ #17147 stays OPEN — this PR is not its closer. > ⚠️ Worded this way deliberately. The earlier phrasing put a closing keyword immediately before the number, and GitHub's reference parser matches the keyword plus the number and ignores the negation around it — so on #17753's merge the card was auto-closed as COMPLETED (reopened since; see that PR's body). Clause-②: no — no new key lands on any published payload. Two test-case titles, one test header note, one widened assertion in a test file, one changeset. ## What the single-file pin missed #17753's negative assertion read `plugin-permission-enforcer.ts` and checked the retracted sentence was gone from it. It was. But `packages/runtime/src/security/artifact-granted-permissions.test.ts` — the file #13457 added — carried the same phrasing as a **case title**: > `it('a CONSENTED entry enforces exactly the consented surface and nothing beside it', …)` next to a sibling titled `… — registered, and denies`. **Neither case asserts a refusal, and neither could.** Both read a permission bag through `getPluginPermissions` and check what it *answers*; nothing on the tree queries that registry, because `SecurePluginContext` has no production construction site and the fs/network gates have no caller at all. A case title is read as evidence (ADR-0033) — those two told a reader the platform confines plugins, which is exactly the defect #17147 exists to remove, in the one place a `grep` for the *docblock* would never look. ## The fix, and why the pin changes shape - Both titles now name what they assert: `bag ANSWERS yes to …` / `its bag answers NO to everything`. - That file's header states the verb discipline out loud: **`answers` / `registered` / `bound`**, ⛔ never `enforces` / `denies` / `gates` / `refuses` / `blocks` until the seam exists — and points at the pin that decides when it does. - `granted-permissions-not-enforced.pin.test.ts`'s negative assertion becomes a **repo-wide `git grep`** over the same pathspecs as its other sweeps, excluding only its own specimen. The needle is held once as `RETRACTED` so the sweep and the single-file read cannot drift apart. - **Anti-vacuity limb:** the raw result must still *contain* this file's own specimen, so a scan that is broken or looking at nothing cannot pass as a clean repo — `.filter` alone would hide both. **Ablated:** restoring the old case title turns the sweep red and names the offending file. `check:cross-package-test-inputs` still OK (28 packages); `@objectstack/core` `test:repo` and `@objectstack/runtime` `src/security` both green (6 and 141 tests). ## The general lesson, recorded A text pin that reads **one file** proves that file. This claim lived in six carriers across three repos, and the cheap correct shape was a sweep with an anti-vacuity control from the start. Refs: #17147 · #13457 · PR #17753 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent e4e22c7 commit 6548118

3 files changed

Lines changed: 60 additions & 3 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@objectstack/core': patch
3+
---
4+
5+
Sweep the retracted "enforces exactly the consented surface" phrasing repo-wide, not just in the file it shipped on.
6+
7+
The #17147 pin read one file, and a post-merge sweep found what that missed: `artifact-granted-permissions.test.ts` carried the retracted sentence as a CASE TITLE — "a CONSENTED entry enforces exactly the consented surface" — beside a sibling titled "registered, and denies". Neither case asserts a refusal; both read a permission bag and check what it answers. But a case title is read as evidence (ADR-0033), and those two said the platform confines plugins while nothing on the tree queries the registry at all.
8+
9+
Both titles now name what they assert, the file carries a verb-discipline note (`answers` / `registered` / `bound`; ⛔ never `enforces` / `denies` / `gates` / `refuses` / `blocks` until the seam exists), and the pin's negative assertion is a repo-wide `git grep` excluding only its own specimen — with an anti-vacuity limb so a broken scan cannot read as a clean one.
10+
11+
No behaviour, no assertion semantics, and no accept/reject changes.

‎packages/core/src/security/granted-permissions-not-enforced.pin.test.ts‎

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ const toRepoPath = (absolute: string) => relative(REPO_ROOT, absolute).split(sep
6262
/** The file that declares the enforcer, the secure context and every gate. */
6363
const HOME = toRepoPath(join(HERE, 'plugin-permission-enforcer.ts'));
6464

65+
/** This file, so the repo-wide sweep below can exclude its own specimen. */
66+
const SELF = toRepoPath(fileURLToPath(import.meta.url));
67+
68+
/**
69+
* The retracted claim, as data. It shipped on the enforcer docblock and — found
70+
* only by a post-merge sweep — as a case title in the runtime's seam test. Held
71+
* once so the sweep and the single-file read cannot drift apart.
72+
*/
73+
const RETRACTED = 'enforces exactly the consented surface';
74+
6575
/**
6676
* Generous on purpose: the scan costs tens of milliseconds, but a merge-queue
6777
* runner doing a full monorepo build at the same time can starve it, and a pin
@@ -169,9 +179,32 @@ describe('[#17147] the install-time granted permission set is registered, not en
169179
expect(
170180
text,
171181
'the retracted sentence must not come back beside the truthful one',
172-
).not.toContain('enforces exactly the consented surface');
182+
).not.toContain(RETRACTED);
173183
});
174184

185+
it('the retracted phrasing is absent from the WHOLE repo, not just its own file', () => {
186+
// [#17147 follow-up] The single-file version above missed one: the runtime's
187+
// own seam test carried `a CONSENTED entry enforces exactly the consented
188+
// surface` as a CASE TITLE. Nothing in it asserted a refusal — it reads a
189+
// permission bag and checks what the bag answers — but a case title is read
190+
// as evidence (ADR-0033), and that one said the platform confines plugins.
191+
// Found by a post-merge sweep, not by this pin, which is why the pin now
192+
// sweeps instead of reading one file.
193+
const offenders = gitGrep(RETRACTED).filter((p) => p !== SELF);
194+
195+
expect(
196+
offenders,
197+
'the retracted phrasing came back somewhere. It says the platform confines a plugin, '
198+
+ 'which it does not — see this file\'s header for the measurement, and use `answers` / '
199+
+ '`registered` / `bound` instead.',
200+
).toEqual([]);
201+
202+
// Anti-vacuity: this file itself carries the needle, so a scan that saw the
203+
// tree must return at least SELF. An empty raw result means the scan is
204+
// broken or the file is untracked, and `.filter` would hide both.
205+
expect(gitGrep(RETRACTED), 'the scan did not even see this file').toContain(SELF);
206+
}, SCAN_TIMEOUT_MS);
207+
175208
it('registers a grant without gating anything — the behaviour the text describes', async () => {
176209
// Anti-vacuity for the prose above: assert the FACT, not only the sentence.
177210
const { createPluginPermissionEnforcer } = await import('./plugin-permission-enforcer.js');

‎packages/runtime/src/security/artifact-granted-permissions.test.ts‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@
1414
// asserted through the enforcer's OWN readback (`getPluginPermissions`), never
1515
// through the binding record alone — the binding record is what this module
1616
// says it did, the enforcer is what actually happened.
17+
//
18+
// ⛔ VERB DISCIPLINE (#17147). Every case here reads a permission BAG and
19+
// asserts what it ANSWERS. None of them asserts that anything was refused, and
20+
// none of them could: nothing on this tree queries the registry these entries
21+
// land in — `SecurePluginContext` has no production construction site, and the
22+
// fs/network gates have no caller at all. Two case titles here used to say
23+
// `enforces` and `denies`, and a case title is read as evidence (ADR-0033: an
24+
// AI author reading this file concludes the platform confines plugins and
25+
// writes a manifest expecting it). So: `answers`, `registered`, `bound` — ⛔
26+
// never `enforces`, `denies`, `gates`, `refuses` or `blocks` until the seam
27+
// exists. The measurement that decides when it does is pinned in
28+
// `@objectstack/core`'s `granted-permissions-not-enforced.pin.test.ts`, whose
29+
// negative assertion is repo-wide and covers this file too.
1730

1831
import { describe, it, expect, vi } from 'vitest';
1932
import { createPluginPermissionEnforcer } from '@objectstack/core';
@@ -87,7 +100,7 @@ describe('#13457 — absent, `{}`, and consented are THREE states, never two', (
87100
expect(binding.unregistered).toEqual(['com.acme.crm', 'com.acme.reports']);
88101
});
89102

90-
it('a `{}` ENTRY is a consent record that consented to nothing — registered, and denies', () => {
103+
it('a `{}` ENTRY is a consent record that consented to nothing — registered, and its bag answers NO to everything', () => {
91104
const e = enforcer();
92105
const binding = registerArtifactGrantedPermissions(
93106
artifact({ grantedPermissions: { 'com.acme.crm': {} } }),
@@ -106,7 +119,7 @@ describe('#13457 — absent, `{}`, and consented are THREE states, never two', (
106119
expect(perms!.canReadFile('/tmp/x')).toBe(false);
107120
});
108121

109-
it('a CONSENTED entry enforces exactly the consented surface and nothing beside it', () => {
122+
it("a CONSENTED entry's bag ANSWERS yes to exactly the consented surface and nothing beside it", () => {
110123
const e = enforcer();
111124
registerArtifactGrantedPermissions(
112125
artifact({ grantedPermissions: { 'com.acme.crm': CONSENTED } }),

0 commit comments

Comments
 (0)