Skip to content

[finding] merge=os-regen cannot be wired for a root-owned generated artifact — git-merge-regen resolves gen:/check: names in packages/spec only #13585

Description

@claude

Found while building the tenant-audit census artifact (#13548). No severity asserted; this records what was driven and what came back.

The shape

merge=os-regen is the repo's protection for generator-owned artifacts: a whole-file-regenerated artifact whose text merge is plausible and wrong. Registering a path requires two halves that check:merge-driver reconciles both ways — a .gitattributes route, and a row in scripts/regen-artifacts.mjs carrying gen: / check: script names.

Those script names are resolved in packages/spec/package.json and nowhere else. From scripts/git-merge-regen.mjs:

functionreconcileScripts(){constpkg=join(REPO_ROOT,'packages/spec/package.json');if(!existsSync(pkg))returnfail('packages/spec/package.json not found');constscripts=JSON.parse(readFileSync(pkg,'utf8')).scripts??{};

So an artifact owned by ROOT-level tooling (scripts/*.mjs, root package.json scripts) cannot be registered at all, however exactly it matches the pathology the driver exists for.

What was measured

Registering docs/audits/2026-08-tenant-audit-write-call-sites.counts.md — a whole-file-regenerated ledger with root-level gen:/check: scripts — was attempted and backed out. With the root scripts added, the .gitattributes line added and the table row added:

✓ .gitattributes ↔ regen-artifacts.mjs agree on 14 path(s)
✗ script(s) named by the table no longer exist in @objectstack/spec:
docs/audits/2026-08-tenant-audit-write-call-sites.counts.md → gen:tenant-audit-census
docs/audits/2026-08-tenant-audit-write-call-sites.counts.md → check:tenant-audit-census
✗ merge driver wiring is inconsistent — see above.

The three edits were reverted; the artifact ships unprotected, with the limitation stated in its own header and the drift gate as the backstop (a wrongly merged file fails loudly rather than silently).

Why this is worth a card rather than a shrug

The refusal is correct about the tree and wrong about the world: it reads as "you named a script that does not exist" when the truth is "this artifact is not owned by packages/spec". An author following it literally would move root tooling scripts into a package they do not belong to, purely to satisfy a lookup path.

Every one of the 14 currently-registered paths happens to be spec-owned or spec-adjacent, which is why the assumption has held. It is an assumption, not a constraint — docs/protocol-upgrade-guide.md is already outside packages/, and only its scripts are inside.

Suggested shape, not a prescription

Resolve each row's gen:/check: against the root manifest as well as packages/spec — or let a row declare its owning package — and have the refusal say which manifests were searched.

Related, and distinct


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions