Skip to content

Close the 0.2.4 tech-debt batch: secret scan, silent drops, orphan-drift, atomic import - #11

Merged
llima merged 14 commits into
mainfrom
chore/tech-debt-batch-0-2-4
Sep 25, 2026
Merged

llima merged 14 commits into
mainfrom
chore/tech-debt-batch-0-2-4

Conversation

@llima

@llima llima commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Summary

  • Version bumped to 0.2.4. Merging publishes craftar@0.2.4 to npm after approval in the npm environment.
  • Secret scan: UTF-16 sources with a byte-order mark are now decoded and scanned (previously skipped or read as mojibake). The Azure DevOps PAT pattern requires a digit in the 52-char form, treats _ as a boundary, and adds the 84-char AZDO format.
  • Nothing dropped silently: claude-code warns on a steering ingredient explicitly aimed at it; agents-md warns for every non-rule ingredient aimed at it, one line per type naming each skipped ref. AGENTS.md bytes are pinned by exact-bytes, variant and EOL tests written before the emitter change.
  • orphan-drift stays visible: a hand-edited orphan keeps its lock entry until the file is deleted, like drift.
  • Atomic import: every Forge write is staged in memory and flushed only after all reads and checks pass, so a failed import leaves the Forge untouched and says so. An I/O error during the final flush still lists the paths already written (accepted residual).
  • Test harness: the tsx loader is resolved through Node instead of a hardcoded dist/ path.

What users will see

  • No emitted bytes change for claude-code, kiro or agents-md.
  • craftar.lock changes only for a workspace with a file in orphan-drift; there sync --check now keeps exiting 1 until the file is deleted (before, it passed after one sync).
  • Profiles targeting agents-md with agents, commands, skills or MCP servers at the default targets: "*" get new warning lines (one per type). Exit codes are unchanged.
  • An import that previously went through with a secret inside a UTF-16 file, or with an 84-char Azure DevOps PAT, is now rejected for that ingredient.

Test plan

  • npm run typecheck — passes
  • npm test (Linux, local) — 19 files passed / 1 skipped; 348 tests passed / 5 skipped. skipIf(win32) tests ran.
  • Oracle skipped — no fixture on this machine; the import path now writes through a stage, and the byte claim rests on the importer tests and the pinned AGENTS.md bytes
  • CI green on Linux and Windows (Windows not run locally; the tsx loader change needs it)
  • node-cli-reviewer and docs-author: clean after one correction round (README UTF-16 wording, 163a30e)

…ing it

runCli and the unify golden regen script pointed --import at tsx's internal
dist/loader.mjs; a tsx upgrade that moves it would break every CLI test.
Resolve tsx's exports["."] from the repository in one shared helper instead.
…r format

A 52-letter lowercase run or a run inside a snake_case identifier was flagged as a PAT,
while the 84-char format Azure DevOps issues since sprint 241 was not caught at all.
UTF-16 text was taken for binary (NUL bytes) and skipped, or read as UTF-8 mojibake no
pattern matches, so a token in it reached the Forge. The decode is for scanning only.
…S.md

The emitter's output was only checked with toContain, so a reordered section or an
extra blank line passed. Pinning it first proves the warning change that follows
emits identical bytes.
…code

A steering ingredient with targets "*" reached the claude-code switch and was
discarded by a bare break. It is now skipped with a warning; emitted bytes are unchanged.
The emitter filtered down to rules up front, so agents, commands, skills, mcp,
scripts, hooks and steering aimed at it vanished without a word. Each is now
skipped with a warning; the pinned AGENTS.md bytes are unchanged.
The Targets section now says which ingredients each emitter cannot express,
matching the kiro paragraph, plus the EOL/BOM contract AGENTS.md follows.
apply() dropped orphan-drift from the rewritten lock, so the file was reported
once and then forgotten. It now keeps the old entry, as drift does, until the
user deletes the file; tests cover two syncs and sync --check.
An import that threw partway (a cyclic existing ingredient, a bad .mcp.json) left the
ingredients already written orphaned in the Forge. Writes now go to an in-memory overlay and
reach disk only after the run is planned; the error says the Forge was left untouched.
Seeds a cyclic existing MCP ingredient so the run fails after a rule was already planned,
and checks the Forge bytes, the missing Forge directory and the CLI message. A third case
pins that a staged ingredient is compared against exactly as a written one was.
The import row now names the guarantee the importer holds, so users know a failed run
needs no cleanup before it is re-run.
The default targets "*" aims a whole profile at agents-md, so one warning per
ingredient buried the rest; each line still names every skipped ref.
The import row still claimed UTF-16 files were not scanned, which f120c5f made false.
@llima
llima merged commit 74ffc93 into main Sep 25, 2026
8 checks passed
@llima
llima deleted the chore/tech-debt-batch-0-2-4 branch September 25, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant