Skip to content

Commit 24135ab

Browse files
os-steveclaude
andauthored
fix(skills): retire the four root-devdep rows by unmarking their fences (#7557) (#7568)
The root-manifest bound (#7554) refused four MARKED fences in skills/objectui/guides/testing.md and carried them as shrink-only debt in KNOWN_ROOT_DEVDEP_EXAMPLES. A declared row is uncovered debt, not a green: every run printed "13 of 17 ts fence(s) judged". Measured first, per the card's two options. check-skill-examples.mjs reads exactly ONE declaration on a fence -- MARKER, an exact-string match on the whole line, with no reason field, no install field and no capture group -- and check-doc-snippet-types.mjs's FRAGMENT_MARKER is not read by it at all (the word appears twice in the file, both times in prose about the docs gate's opposite opt-OUT design, never in code). The bound itself, resolvesOnlyThroughRootManifest, is a pure function of the specifier and two repository-wide maps with no per-block parameter to declare into. So there is no form in which a fence keeps its mark and names its install, and even the docs gate's fragment form routes a block AWAY from the compiled set -- the same coverage loss as the row, under a different name. That selects option 2. - unmark the four fences, reason written beside each: vitest and @playwright/test are the reader's own installs, not packages this repository publishes; - delete all four rows, leaving KNOWN_ROOT_DEVDEP_EXAMPLES empty, with its docblock recording the measurement and when a NEW row is still right; - lower MARKED_FLOOR ts 17 -> 13, reason beside the row, in this same PR -- the move #7550's ratchet allows only here. Not a precedent for unmarking a red fence: these four were type-checked by nothing at all for the whole of their life as rows. Before: Root bound 4 refused, 4 rows declared; Semantic phase 13 of 17. After: Root bound refuses nothing; Semantic phase 13 of 13; Marked 13 ts (floor 13), 39 json (floor 39). Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox Co-authored-by: Claude <noreply@anthropic.com>
1 parent d06ca4a commit 24135ab

2 files changed

Lines changed: 71 additions & 40 deletions

File tree

‎scripts/check-skill-examples.mjs‎

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,14 @@
152152
* harness's `moduleSpecifiersOfBlock`, so the line cannot name a specifier no
153153
* fence imports, and the suite pins that the two sets agree over this corpus.
154154
*
155-
* ⚠️ A refused fence is NOT type-checked. The four pre-existing ones are carried
156-
* in the shrink-only `KNOWN_ROOT_DEVDEP_EXAMPLES` below so the bound landed with
157-
* zero new red, and the `Root bound` and `Semantic phase` lines both say how
158-
* many fences that costs — a declared row is uncovered debt, never a green.
155+
* ⚠️ A refused fence is NOT type-checked. The four pre-existing ones were
156+
* carried in the shrink-only `KNOWN_ROOT_DEVDEP_EXAMPLES` below so the bound
157+
* landed with zero new red, and the `Root bound` and `Semantic phase` lines both
158+
* say how many fences that costs — a declared row is uncovered debt, never a
159+
* green. Those four were retired in objectui#7557 by unmarking their fences, so
160+
* that list is now EMPTY and the bound refuses nothing; see its docblock for the
161+
* measurement that chose unmarking over declaring, and for when a NEW row is
162+
* still the right answer.
159163
*
160164
* The cost of that decision is the PRECONDITION, and it is a declared exit code
161165
* rather than a silent green: if a package a marked fence imports has no `dist`,
@@ -283,11 +287,13 @@
283287
* and guessing it is what produces a gate people learn to ignore.
284288
* 2. **Whether a REFUSED fence's example is correct.** The root bound says
285289
* only that this gate cannot reach the package the fence imports, never
286-
* that the fence is wrong — the four declared rows are good documentation
287-
* about test runners the reader installs. Retiring a row means giving the
288-
* example an import the reader provably has, or the guide's owner deciding
289-
* the fence should not be gated; both are skills judgements over a GOVERNED
290-
* surface, made in a skills PR.
290+
* that the fence is wrong — the four rows it once declared were good
291+
* documentation about test runners the reader installs, which is why
292+
* objectui#7557 retired them by unmarking the fences rather than by editing
293+
* the examples. Retiring a row means giving the example an import the
294+
* reader provably has, or the guide's owner deciding the fence should not
295+
* be gated; both are skills judgements over a GOVERNED surface, made in a
296+
* skills PR.
291297
* 3. **Whether an eval's `must_contain` token is taught by the guides.** A
292298
* different oracle over a different corpus, discussed at length on
293299
* objectui#7359 and explicitly not this check.
@@ -419,8 +425,11 @@ export const EXIT_CODES = {
419425
* row — which example stopped being one, and why unmarking it was the
420426
* honest call rather than the cheap way out of a red.
421427
*
422-
* There is no row-with-a-reason yet, because nothing has been unmarked since
423-
* the gate landed. The first one to lower a number writes it here.
428+
* The first lowering is `ts` 17 -> 13 (objectui#7557), and its reason is on the
429+
* row itself below. Read it as the worked example of what this section asks
430+
* for: the four fences it names were marked over imports the harness cannot
431+
* reach, so their marks were claims no run could honour — the honest move was
432+
* to withdraw the claim in the guide, not to carry it as debt forever.
424433
*
425434
* ## What this floor counts, and what the OTHER ratchet counts
426435
*
@@ -438,7 +447,19 @@ export const EXIT_CODES = {
438447
* @type {ReadonlyMap<string, number>}
439448
*/
440449
export const MARKED_FLOOR = new Map([
441-
['ts', 17],
450+
// 17 -> 13 (objectui#7557): the four marked fences in
451+
// `skills/objectui/guides/testing.md` that imported `vitest` (`:60`, `:94`,
452+
// `:218`) or `@playwright/test` (`:258`) were unmarked, with the reason
453+
// written beside each fence. Those two are TEST RUNNERS the reader installs
454+
// in their own project and no package this repository publishes declares
455+
// either, so the root bound refused all four and NOTHING type-checked them —
456+
// their markers claimed a check that could not run, and the four rows in
457+
// `KNOWN_ROOT_DEVDEP_EXAMPLES` below (now empty) were that claim's standing
458+
// cost. Unmarking is the honest call here and not the cheap way out of a red:
459+
// the marks were not hiding a broken example, they were over-stating this
460+
// gate's reach, and the guide already carried five UNMARKED `vitest` fences
461+
// beside them. ⛔ Not a precedent for unmarking a fence that reds.
462+
['ts', 13],
442463
['json', 39],
443464
]);
444465

@@ -559,36 +580,46 @@ export function bareAnyRowKey(block, finding) {
559580
* same direction, and the same reasoning, as `KNOWN_BARE_ANY_EXAMPLES` above.
560581
*
561582
* The corpus at the bound's branch point was FOUR rows, all in one guide, all
562-
* measured before the bound was armed. Each one is real documentation the gate
563-
* cannot verify rather than a defect:
583+
* measured before the bound was armed:
564584
*
565-
* - `testing.md:60`, `:94`, `:218` import `vitest`, and `:258` imports
585+
* - `testing.md:60`, `:94`, `:218` imported `vitest`, and `:258` imported
566586
* `@playwright/test`. Both are TEST RUNNERS the reader installs in their own
567587
* project — the guide's first sentence names both — and no package this
568-
* repository publishes declares either, so nothing in the map covers them.
569-
* They compiled until now only because THIS repository carries both as root
570-
* devDependencies, which is the leak the bound closed.
571-
*
572-
* ⛔ Why they are declared here rather than unmarked in the guide: the guides
573-
* under `skills/**` are a GOVERNED surface (see `AGENTS.md`), and removing a
574-
* marker to make a gate green is the "gate weakens the guide to suit itself"
575-
* move the shrink-only lists exist to prevent. It would also breach
576-
* `MARKED_FLOOR` above, which counts MARKS: a declared row here leaves the
577-
* marked population exactly where it was, because the fence is still marked —
578-
* these two ratchets count different things on purpose, and neither one
579-
* substitutes for the other. Retiring a row means giving the
580-
* example an import the reader provably has, or the guide's owner deciding the
581-
* fence should not be gated — either way a skills judgement, made in a skills
582-
* PR, not in this one.
588+
* repository publishes declares either, so nothing in the map covered them.
589+
* They compiled until the bound only because THIS repository carries both as
590+
* root devDependencies, which is the leak the bound closed.
591+
*
592+
* ## The list is EMPTY, and that is the terminal state (objectui#7557)
593+
*
594+
* All four rows are retired. The bound's own card left the choice to the guide's
595+
* owner and it was made by MEASUREMENT rather than by taste: this gate reads
596+
* exactly ONE declaration on a fence — `MARKER` above, an exact-string match on
597+
* the whole line, with no reason field, no install field and no capture group —
598+
* and `check-doc-snippet-types.mjs`'s `FRAGMENT_MARKER` is not read here at all.
599+
* The bound itself (`resolvesOnlyThroughRootManifest`) is a pure function of the
600+
* specifier and two repository-wide maps, with no per-block parameter to declare
601+
* into. So there was no form in which a fence could keep its mark and name its
602+
* install, and the four fences were unmarked in `testing.md` with the reason
603+
* written beside each. `MARKED_FLOOR` above records the matching `ts` 17 -> 13.
604+
*
605+
* ⚠️ This is NOT the precedent it can be misread as. Unmarking to silence a red
606+
* is the "gate weakens the guide to suit itself" move these shrink-only lists
607+
* exist to prevent, and it stays refused. What was withdrawn here was different:
608+
* a mark over a fence the harness REFUSES is a claim no run can honour — those
609+
* four were type-checked by nothing at all for the whole of their life as rows,
610+
* and the summary said so on every run. The two ratchets still count different
611+
* things on purpose, and neither substitutes for the other.
612+
*
613+
* A NEW row may still be declared if the bound ever refuses a marked fence
614+
* again — the machinery below is live, and `judge()` reds an undeclared refusal.
615+
* But a row is uncovered debt, never a green, so the first question stays: can
616+
* this example import what the reader provably has? Declare a row only when the
617+
* answer is no AND the fence must keep its mark for some reason this comment
618+
* does not anticipate; otherwise unmark it here, the way these four were.
583619
*
584620
* @type {ReadonlySet<string>}
585621
*/
586-
export const KNOWN_ROOT_DEVDEP_EXAMPLES = new Set([
587-
'skills/objectui/guides/testing.md:60 vitest',
588-
'skills/objectui/guides/testing.md:94 vitest',
589-
'skills/objectui/guides/testing.md:218 vitest',
590-
'skills/objectui/guides/testing.md:258 @playwright/test',
591-
]);
622+
export const KNOWN_ROOT_DEVDEP_EXAMPLES = new Set([]);
592623

593624
/** The debt-list key for one refused specifier in one fence. */
594625
export function rootDevDepRowKey(block, specifier) {

‎skills/objectui/guides/testing.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ describe('plugin-kanban registration', () => {
5656

5757
### Pattern 3: Schema validation testing
5858

59-
<!-- os:check -->
59+
<!-- Not opted into the example gate: `vitest` is a test runner the reader installs in their own project, not a package this repository publishes, so there is nothing here to type-check this block against. -->
6060
```typescript
6161
import { describe, it, expect } from 'vitest';
6262
import { validateSchema, isValidSchema, formatValidationErrors } from '@object-ui/core';
@@ -90,7 +90,7 @@ describe('schema validation', () => {
9090

9191
### Pattern 4: Expression evaluation testing
9292

93-
<!-- os:check -->
93+
<!-- Not opted into the example gate: `vitest` is a test runner the reader installs in their own project, not a package this repository publishes, so there is nothing here to type-check this block against. -->
9494
```typescript
9595
import { describe, it, expect } from 'vitest';
9696
import { ExpressionEvaluator } from '@object-ui/core';
@@ -214,7 +214,7 @@ describe('AuthProvider', () => {
214214

215215
### Pattern 7: DataSource adapter testing
216216

217-
<!-- os:check -->
217+
<!-- Not opted into the example gate: `vitest` is a test runner the reader installs in their own project, not a package this repository publishes, so there is nothing here to type-check this block against. -->
218218
```typescript
219219
import { describe, it, expect, vi, beforeEach } from 'vitest';
220220
import { ObjectStackAdapter } from '@object-ui/data-objectstack';
@@ -254,7 +254,7 @@ describe('ObjectStackAdapter', () => {
254254

255255
### Smoke test
256256

257-
<!-- os:check -->
257+
<!-- Not opted into the example gate: `@playwright/test` is a test runner the reader installs in their own project, not a package this repository publishes, so there is nothing here to type-check this block against. -->
258258
```typescript
259259
import { test, expect } from '@playwright/test';
260260

0 commit comments

Comments
 (0)