mirror of
https://github.com/zernie/vigiles.git
synced 2026-09-14 20:53:57 +08:00
v1
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f52fa12c4f |
fix(lint): spec-refs reaches every compiled surface, and compile emits prettier-clean artifacts (#195)
Closes #190. spec-refs re-derives a compiled file's references from its spec, but called compileClaude directly and skipped every spec whose _specType was not "claude". Four of the five compiled surfaces — skills, subagents, railway orchestrators, generated harness files — got no re-derivation at lint time, so an artifact committed while its refs were live stayed green forever after the target was deleted. Measured here: compile reported `Skill not found` on examples/SKILL.md while lint reported `hash valid`. Smaller than the issue estimated. #190 expected a per-type ref accessor because each compiler reaches its refs differently; they do not — all four already return the same errors: CompileError[], and only the options differ. One exhaustive dispatcher, so a fifth spec type is a tsc error rather than a silent skip. compile also emitted artifacts that prettier --check then rejected, on all seven examples/ artifacts — which is why they sat un-recompiled carrying a retired marker position, and which blocked the fix above. Two independent defects: both frontmatter renderers padded inside the --- fence, and the frontmatter/body join added a blank line placeIntegrityHeader then added again. Fixed at the join, not in the stamper: seal hashes the content it receives, so trimming there hashes one string and writes another (measured — it broke integrity on three artifacts). Also: check.mjs now declares and prints the CI jobs it does NOT run, with a test asserting that list against ci.yml. It covered one job of six while its name and its "18/18 passed" read like all of them, and that cost a cycle. The test earned itself immediately — the hand-written list missed e2e and named two commands that do not exist. Also: @openai/codex is pinned. latest was 0.153.1, whose tarball 404s while its metadata still resolves, so the install step failed on every branch until pinned. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
900dc7e06a |
refactor(spec)!: name things for what they are; retire the vigiles/experimental subpath (#169)
Three exported symbols were named for something other than what they are, and
two mechanisms were doing one job.
RENAMES (old names kept one major, @deprecated, removed one major AFTER this one):
claude() → instructionFile() compiles CLAUDE.md AND AGENTS.md, so a
name from one harness was never right
instructions`` → prose`` builds a prose FRAGMENT; the plural read
as "the instruction file", which is what
instructionFile() builds
agent() → experimental_agent() the shape is not settled, and the tag was
never there (git log -S empty)
SkillSpec.result: → postcondition: `result` already meant the subagent output
contract one screen down; the doc comment
had to spend a line disambiguating them
The alias window is not politeness. Measured: the previous rename shipped with
ZERO overlap (18.1.1 old names only, 19.0.0 new only). A container rollback put
the old node_modules under new sources, PreToolUse stopped loading, and a
PreToolUse that does not load denies EVERY Bash command — including the one that
fixes it. One window per major makes that pair unrepresentable.
SUBPATH RETIRED. vigiles/experimental is gone; its members moved to the door
their feature already uses. Of two mechanisms for one promise the subpath was the
weaker: it marks the import line, out of view by the time anyone reads the call.
Measured on the only user-facing example — with the prefix aliased away at
import, the marker survived at 0 of 5 call sites. So the prefix stays, the advice
to alias it away became an explicit prohibition, and the six define* entry points
are DECLARED prefixed rather than gaining it at re-export.
That de-aliasing is what unblocked moving the naming check into ESLint, and the
ORDER was load-bearing: measured before it, dropping the public/internal
exemption produced 14 findings, all from the re-export indirection. Measured
after, across all of src/ with no exemption: 22 tagged declarations, 0
unprefixed. The rule turns on silent.
EXPORT CLEANUP. vigiles/linting export * → curated, 103 → 79 symbols; its header
claimed to be curated with an `export *` one line below, and claimed the builders
were also at the package root (191 exports there, zero matches). ClaudeTool and
HookEvent deleted — zero references, and both had drifted off the dialect they
claimed to mirror; HookEvent listed 5 events, two of which do not exist, against
the 31 the vendor documents.
DOCS. experimental.md deleted and distributed per feature: the skill half into
skills.md §Status, the hook half into a new compiled-hooks.md §Status, and the
emit half — 111 of its 177 lines, a topic doc wearing a stability page's clothes
— into docs/emit-channel.md, which gains the "which channel when" comparison it
never had. The one cross-cutting sentence went to the README.
TWO GATES WERE GREEN AND WRONG, both found by this work:
- api:check reported "verified for 11 entries — no drift" while reading
dist/experimental.d.ts from a PREVIOUS build (tsc does not clean dist/) for a
source file that no longer existed. Now asserted against package.json
exports, with a mutation proving exit 1 on a phantom entry.
- check-export-prefixes caught MY error: the R3 services first landed on
vigiles/eval, where `paid_` means "this call can bill you" — and
startServices takes a ContainerRuntime and calls no model. Naming it
paid_experimental_startServices would have redefined paid_ as "expensive in
some sense". They went to the package root.
SEVENTEEN review findings landed on this branch, all real. Two mechanical
closures came out of them: src/example-imports.test.ts resolves every relative
import under examples/ instead of matching a string, and the naming rule now
ENUMERATES the three export paths it visits rather than describing its coverage
in the abstract. One attempt is recorded as REFUTED: teaching the doc gate to
flag our own exports as free variables measured 66 findings across 93 blocks, so
that gate's original scoping was right.
BREAKING CHANGE: vigiles/experimental is removed. Its exports are unchanged in
name and behaviour and are now reached from `vigiles` (the emit channel, the R3
disposable-service tier). Every renamed symbol keeps a working @deprecated alias
for this major.
|
||
|
|
34a4f7a556 |
fix: no raw NUL bytes in source, and a gate that keeps it that way (#160)
src/scan-files.test.ts carried two literal NUL bytes inside a template literal where the escape was meant. Git decides "binary" per blob by looking for a NUL, and a binary blob gets no line diff and NO THREE-WAY MERGE — so every branch touching the file conflicted, unresolvably, because there were no hunks to pick. Measured: with the bytes escaped, `main <- fix-scan` and `main <- fix-shadow` each merge with ZERO conflicts. They had been parked for a day as "conflicting with each other"; they never were. The escape is the form the rest of the codebase already uses (skill-contract, scan-core, coverage-artifact, coverage-probe — eight sites), and the string it produces is byte-identical, so scan-files.test.ts still passes its 21 tests. Adds scripts/check-text-sources.mjs as an 18th `check` gate. It refuses to pass on an empty scan, since a scan finding nothing is indistinguishable from a scan looking in the wrong place. Proven by mutation: planting one raw NUL fails it with the file, the count and the offset. Not a .gitattributes marker: that restores diff and merge while leaving the byte in the source, hiding the defect instead of removing it. Claude-Session: https://claude.ai/code/session_01Uvk2Zx66BAuxuLGLFL2umd Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
1ebef8320a |
ci: one list of commands instead of two — CI now calls npm run check (#151)
* ci: один список команд вместо двух — CI зовёт `npm run check` Сегодня три PR уехали в `main` красными: список гейтов гонялся по памяти (пять команд), а джоб `check` гонял тринадцать. Упавшая — `tsc -p test/types/tsconfig.json` — живёт в ОТДЕЛЬНОМ tsconfig, которого корневой тайпчек не видит, и три `@ts-expect-error`-ассерта тихо перестали срабатывать. Длинный список, который надо помнить, это не чинит. Чинит то, что список СТАЛ ОДИН и CI его ВЫЗЫВАЕТ: `scripts/check.mjs` + `run: npm run check` вместо тринадцати шагов. Это стандартный паттерн поля (pre-commit / just / mise): определение задач — источник правды, CI его дёргает. Прежняя моя идея «завести гейт на совпадение двух списков» снята: она была подпоркой под дубль, который правильнее убрать. Стадии несущие, а не косметика. Часть команд ПИШЕТ файлы, которые другие ЧИТАЮТ (`generate types` → `.vigiles/generated.d.ts`, `api-extractor` → `api-surface/*`, `build` → `dist/`), поэтому писатели сериализованы, а параллельно идёт только read-only группа. 17/17 за 70 с против ~3 мин последовательно. Имена падающих шагов не потеряны — раннер печатает, что именно упало, и `--list` показывает команды без запуска. 🔴 Два шага `uses: ./` НЕ входят в `npm run check` намеренно: они догфудят собственный composite Action, у которого нет shell-эквивалента. Один из них (`eval-check`) при первой правке был снесён случайно — он стоял между двумя command-шагами, и правка по диапазону его проглотила. Возвращён, причина записана прямо над ним. Раннер сразу поймал два собственных промаха: неотформатированный `check.mjs` и протухший `generated.d.ts` после добавления скрипта `check`. Проверено: `npm run check` 17/17 ✓ · ci.yml парсится. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uvk2Zx66BAuxuLGLFL2umd * feat!: словарь скилла уехал на сам билдер — experimental_skill.input/.step BREAKING: `input` и `step` больше не самостоятельные экспорты. Достаются как `experimental_skill.input(…)` / `.step(…)`. Пользователей нет. Зачем. Префикс `experimental_` — привычка, а привычка уже один раз протекла: `skill()` отгрузился со стабильным именем при доке «`skill()` is experimental». На самих `input`/`step` тега и префикса не было вообще, то есть словарь экспериментальной фичи выглядел стабильным. Повесив их на билдер, маркировку делаем СТРУКТУРНОЙ: до `input()` не добраться, не назвав `experimental_skill`. Забрано ровно два символа, и это замер, а не вкус. Перепроверено независимо от вердикта субагента: `input` и `step` встречаются только в скилл-спеках, а `cmd` (5 агентских спек), `file`, `ref`, `result` (8 агентских) общие — их спрятать в неймспейс скилла нельзя. 🔴 По дороге закрыта асимметрия, которую правка иначе бы УХУДШИЛА: дверь `vigiles/claude-code` своих `input`/`step` не экспортировала никогда, и типизированный автор брал их из второй двери. После снятия standalone- экспортов он остался бы без них совсем. Теперь CC-билдер несёт те же хелперы. Форма — `Object.assign`, не `export namespace`: последний запрещён нашим же линтом (`no-namespace: error`). Генерик пережил: в api-репорте `typeof skillSpec & { input; step }`, `ae-forgotten-export` нет. Честная граница записана и в коде, и в доке: `const { input } = experimental_skill` снимает маркер внутри файла. Гарантия у́же — немаркированное имя не пересекает границу пакета. Доки: `docs/skills.md` — пример на алиасе (`experimental_skill as skill`), маркер держится на строке импорта. `docs/experimental.md` — вступление утверждало, что префикс носит всё из `vigiles/experimental`, что после переезда `experimental_skill` в `vigiles/spec` стало неверным; плюс своя секция. `docs/README.md` — доиндексированы `testing-matrix.md` и `non-js-harnesses.md`. `safety.md` намеренно НЕ индексирован: он сам пишет «INTERNAL / WIP — not surfaced in the public docs yet». Гейты: npm run check 17/17 ✓ · vitest 2954 ✓. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uvk2Zx66BAuxuLGLFL2umd --------- Co-authored-by: Claude <noreply@anthropic.com> |