') + ')', 'gi');
if (regex.test(text)) {
found = true;
var frag = document.createDocumentFragment();
var parts = text.split(regex);
parts.forEach(function(part, i) {
if (i % 2 === 0) {
frag.appendChild(document.createTextNode(part));
} else {
var span = document.createElement('span');
span.className = 'userscript-highlight';
span.textContent = part;
frag.appendChild(span);
}
});
node.parentNode.replaceChild(frag, node);
}
});
} else if (node.nodeType === 1 && node.childNodes) { // element
var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];
if (!skipTags.includes(node.tagName)) {
Array.from(node.childNodes).forEach(highlight);
}
}
}
highlight(document.body);
// Re-highlight on dynamic content
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(m) {
m.addedNodes.forEach(function(node) {
if (node.nodeType === 1 || node.nodeType === 3) highlight(node);
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); }
})();
(function(){
try {
var __m = "*";
var __re = new RegExp('^' + ".*" + ', 'i');
if (__m === '*' || __re.test(location.href)) {
// Strip utm_, fbclid, gclid, etc. from all links on page
(function() {
var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',
'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',
'ref', 'ref_src', 'source', 'medium', 'campaign'];
function cleanUrl(url) {
try {
var u = new URL(url, window.location.origin);
var changed = false;
trackingParams.forEach(function(p) {
if (u.searchParams.has(p)) {
u.searchParams.delete(p);
changed = true;
}
});
return changed ? u.toString() : url;
} catch (e) {
return url;
}
}
function cleanLinks() {
document.querySelectorAll('a[href]').forEach(function(a) {
var clean = cleanUrl(a.href);
if (clean !== a.href) a.href = clean;
});
}
cleanLinks();
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(m) {
m.addedNodes.forEach(function(node) {
if (node.nodeType === 1) {
if (node.tagName === 'A') cleanLinks();
node.querySelectorAll('a[href]').forEach(function(a) {
var clean = cleanUrl(a.href);
if (clean !== a.href) a.href = clean;
});
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); }
})();
(function(){
try {
var __m = "youtube.com";
var __re = new RegExp('^' + "youtube\\.com" + ', 'i');
if (__m === '*' || __re.test(location.href)) {
// Auto-enable theater mode on YouTube
(function() {
function tryTheater() {
var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]');
if (btn && !btn.classList.contains('activated')) {
btn.click();
}
}
// Try immediately
tryTheater();
// Try after navigation (SPA)
var lastUrl = location.href;
setInterval(function() {
if (location.href !== lastUrl) {
lastUrl = location.href;
setTimeout(tryTheater, 500);
}
}, 1000);
// Also try on player load
var observer = new MutationObserver(tryTheater);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); }
})();
(function(){
try {
var __m = "*";
var __re = new RegExp('^' + ".*" + ', 'i');
if (__m === '*' || __re.test(location.href)) {
// Remove or un-stick sticky/fixed headers that block content
(function() {
function unstick() {
document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) {
if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {
el.style.position = 'static';
el.style.top = 'auto';
el.style.zIndex = 'auto';
}
});
}
unstick();
var observer = new MutationObserver(unstick);
observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
})();
}
} catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); }
})();
})();
fix(devx): resolve a regen row's gen:/check: in its declared owner, not only in packages/spec by os-project-manager · Pull Request #13616 · objectstack-ai/objectstack · GitHub
You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
git-merge-regen.mjs --self-test resolved every regen row's gen:/check: names in packages/spec/package.json and nowhere else, so an artifact owned by root tooling could not be
registered for merge=os-regen at all — however exactly it matched the pathology the driver exists
for. The refusal was correct about the tree and wrong about the world: it read as "you named a
script that does not exist" when the truth was "this artifact is not owned by packages/spec."
Rows now carry an owner, defaulting to @objectstack/spec — which is what all 13 existing rows
declared implicitly — and the refusal names the manifests it searched.
Verified on 1997df337.
必答項 — is check:merge-driver's reconciliation still two-way?
Yes, and that requirement is what chose the shape of the fix. The answer has two halves.
1. The lookup stayed exact, so nothing became merely permissive
A name is looked for in one manifest — the row's declared owner's — never in "any manifest that
happens to have it". A widened lookup would have made resolution non-deterministic the moment two
manifests defined the same gen: name, and would have accepted a row that names a root-only script
while claiming a package owner. It is pinned as a live case rather than argued: reconcileOwnership() asserts that check:merge-driver, a root-only script name, resolves
under ROOT_OWNER and does not resolve under @objectstack/spec. A permissive lookup passes
every other assertion in that block and fails exactly that one.
Both directions of the .gitattributes ↔ table reconciliation are untouched, and an owner that
resolves to no manifest is a refusal, not a skip — an unresolvable owner means a row whose
scripts were never verified, which is the state this reconciliation exists to make impossible.
2. The half that a one-sided loosening would have left standing — measured, not reasoned
This is the "registered but unreconcilable" seam, and it was real. Two consumers need to know which manifest owns a row, not merely that some manifest has the name:
git-merge-regen.mjsprints a regeneration command at merge time;
check-regen-pending.mjs (the pre-commit gate) spawns one.
Both were bound to packages/spec — the runner's spawn directory was packages/spec
unconditionally. Measured before the owner field existed:
pnpm -s check:sdui-lockstep in packages/spec -> exit 254 ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL Command "check:sdui-lockstep" not found
pnpm -s check:sdui-lockstep at the repo root -> exit 0 check:sdui-lockstep: OK -- ...
So a lookup-only widening would have produced a row that reconciles green and is then
permanently unsatisfiable in the hook. Driven end to end against the real check-regen-pending.mjs, same root-owned row, the only difference being the owner declaration:
A — root-owned row, no owner declared (what a lookup-only widening leaves behind):
HOOK_EXIT=1
✗ packages/sdui-parser/objectui-lockstep.json — stale
pnpm --filter @objectstack/spec gen:sdui-lockstep <- a dead command
Every commit refused, forever, with remedy advice that cannot work.
B — the same row declaring owner: ROOT_OWNER (this PR):
HOOK_EXIT=0
✓ packages/sdui-parser/objectui-lockstep.json — current
os-regen: all deferred artifacts are current — marker cleared.
That is why the owner is declared rather than searched for: one declaration, read by the gate,
the driver's advice and the hook's spawn, so the command the driver prints is the command the gate
runs. Registered-and-unreconcilable is a worse defect than unregisterable, and a widened lookup
alone would have manufactured it.
Non-empty control — rejected before, registered after
The artifact that produced the finding, docs/audits/2026-08-tenant-audit-write-call-sites.counts.md,
lives on PR #13584's branch and is not on main, so it could not be used. The control used instead
is packages/sdui-parser/objectui-lockstep.json with gen:sdui-lockstep / check:sdui-lockstep
— the only root-owned gen:/check: pair in the root manifest on main, i.e. a genuinely
root-owned artifact and not a packages/spec entry testing a path that already worked.
Before the fix (registration attempted on origin/main, then backed out) — the card's exact
refusal shape, reproduced on a different artifact:
✓ .gitattributes ↔ regen-artifacts.mjs agree on 14 path(s)
✗ script(s) named by the table no longer exist in @objectstack/spec:
packages/sdui-parser/objectui-lockstep.json → gen:sdui-lockstep
packages/sdui-parser/objectui-lockstep.json → check:sdui-lockstep
✗ merge driver wiring is inconsistent — see above.
After the fix, same row, still no owner — still refused, because the loosening is not blanket,
and the refusal now names what it searched and points at the right repair:
✗ script(s) named by the table do not exist in their declared owner:
packages/sdui-parser/objectui-lockstep.json → gen:sdui-lockstep [owner @objectstack/spec, packages/spec/package.json]
packages/sdui-parser/objectui-lockstep.json → check:sdui-lockstep [owner @objectstack/spec, packages/spec/package.json]
Manifests searched: @objectstack/spec (packages/spec/package.json)
A row that declares no `owner` defaults to @objectstack/spec, so this can mean the row is
in the wrong package rather than that the script is gone. If ROOT tooling owns the
artifact, declare it — `owner: ROOT_OWNER` in scripts/regen-artifacts.mjs. ⛔ Do NOT move
the scripts into a package to satisfy the lookup: that lets this tool decide code ownership.
After the fix, declaring owner: ROOT_OWNER — registers, and pnpm check:merge-driver is green
end to end (exit 0):
✓ .gitattributes ↔ regen-artifacts.mjs agree on 14 path(s)
✓ all 28 gen:/check: names resolve in their declared owner (@objectstack/spec (packages/spec/package.json), @objectstack/spec-monorepo (package.json))
✓ owner resolution: 11 case(s) pinned, root manifest read as @objectstack/spec-monorepo
...
✓ merge driver wiring is consistent (7 path(s) deliberately excluded).
✓ check-regen-pending self-test passed.
And a third leg, an owner nobody can resolve refuses rather than skipping:
✗ owner(s) named by the table resolve to no manifest:
@objectstack/not-a-package — declared by packages/sdui-parser/objectui-lockstep.json
Unresolved is a REFUSAL, not a skip: those rows' scripts were never verified.
All three registrations were temporary, applied on top of the committed implementation and backed
out with git checkout HEAD -- ...; restoration was proven by an empty git diff HEAD plus a
HEAD-blob-hash comparison per file, not by an exit code.
Why the control artifact is not registered permanently here
packages/sdui-parser/objectui-lockstep.jsoncan now be registered, and deliberately is not. gen:sdui-lockstep re-reads objectui's side, which needs an objectui checkout the merger is not
holding — so the deferred regeneration would be unrunnable at exactly the moment pre-commit demands
it, and the driver only ever defers. Its conflict is also not the shape the driver exists for: the
record holds one side at a named revision, so two branches that each re-recorded it disagree
about which objectui revision the parity was verified against, and no regeneration answers that.
Registering it to give this PR a permanent control would be the test dictating the code, so the
durable guard is reconcileOwnership() instead — it reads the real root manifest through the same
functions the driver and the hook use, on every check:merge-driver run.
The refusal now names which manifests were searched
Per the card: a refusal that misdescribes its own cause sends the reader to the wrong repair. The new
text names the owner and manifest per dead row, lists every manifest searched, states that an
undeclared row defaults to @objectstack/spec, and explicitly refuses the repair the old text
implied — moving root tooling into a package to satisfy a lookup path.
PM mechanism assumptions — verified
"All currently-registered paths are spec-owned or spec-adjacent; the single-manifest assumption
has never been stressed."Confirmed, with a correction to the count. There are 13
registered paths on main, not 14 (the card's 14 was measured with its own candidate row
already added). Ten are under packages/spec/; the other three — docs/protocol-upgrade-guide.md, docs/audits/2026-07-unknown-key-strictness-ledger.counts.md
and content/docs/references/** — are outside packages/. All 13 name scripts defined in packages/spec/package.json, so the assumption held by coincidence of ownership, never by
constraint.
"docs/protocol-upgrade-guide.md is outside packages/ with only its scripts inside — the real
boundary is the manifest, not the artifact path."Confirmed, and stronger than stated: it is
one of three such rows, not one. The boundary was always the manifest.
"The two-way reconciliation is the fragile half; if loosening it cleanly is impossible without a
declared-owner field, say so."Confirmed, and that is the shape delivered. A widened lookup
cannot supply what the driver's advice and the hook's spawn need — which package — so the
declared-owner field is not one of two acceptable options here but the only one that keeps the
reconciliation two-way. See the 必答項 section.
Triage's grading placed #13335 as the symptom of this cause, with this card blocking it. That
blocking relationship does not hold, and the acceptance case could not be run as specified. skills/*/references/_index.md is written by gen:skill-refs and gated by check:skill-refs, and
both of those are defined in packages/spec/package.json (lines 257-258), not in the root
manifest:
So that artifact was never blocked by the single-manifest lookup — it is spec-owned and could
have been registered at any time. Registering it here would therefore have been the vacuous control
this lane rejects: a packages/spec entry exercising a path that already worked. It is also a
disposition question in its own right (route it, or record why it must keep text-merging), which is
the substance of that card and not of this one. #13335 stays open and untouched; nothing under skills/** is in this diff. The card's own body hedged this correctly — "If that card's generator
is also root-owned, this one blocks it" — and it is not.
Verification
Gate family derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
(15 families + 2 convention-triggered for editing a gate script), not guessed. All run at 1997df337:
check:merge-driver — green, including the new ✓ owner resolution: 11 case(s) pinned line
check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check:watch-hint-literal — green
check-ci-filter-parity.mjs, check-cross-package-test-inputs.mjs, check-shard-attestation.mjs — green
bare-root-worklist.mjs --self-test, check:pm-dispatch-gates (the two gate-script conventions) — green
@objectstack/speccheck:generated (all 14 generated artifacts up to date) and check:docs
(230 generated files in sync) — green, after a full spec build
pnpm lint — the whole repo, eslint . --no-inline-config, green. No narrowing claimed.
check:nul-bytes — green; the diff also self-scanned for raw control bytes, none
check-declaration-mirrors.mjs (the .d.mts mirror of the edited runner) — green
The edited gate scripts' consumer suites: dist-freshness.test.ts, schema-tree-freshness.test.ts, build-schemas-check-mode.test.ts — 3 files, 84 tests passed —
plus check:scripts-typecheck — green
check-test-completeness.mjs — NOT MEASURED, by the gate's own declaration: it grades a saved turbo run test log and exits 3 (PREREQUISITE NOT MET) when run without one, which is the shape
the derived family invokes. Not a red.
No changeset: this PR releases nothing from any package — the diff is three root tooling scripts —
so it carries skip-changeset.
…ot only in packages/spec
`git-merge-regen.mjs --self-test` resolved every row's script names in
`packages/spec/package.json` and nowhere else, so an artifact owned by ROOT
tooling could not be registered for `merge=os-regen` at all — however exactly it
matched the pathology the driver exists for. The refusal was correct about the
tree and wrong about the world: it read as "you named a script that does not
exist" when the truth was "this artifact is not owned by packages/spec", and an
author following it literally moves root tooling into a package it does not
belong to, purely to satisfy a lookup path.
Rows now carry an `owner` (defaulting to @objectstack/spec, which is what all 13
declared implicitly), and the refusal names the manifests it searched.
The owner is DECLARED rather than searched for, because a lookup-only widening
would have left the worse half standing. Two consumers need to know WHICH
manifest owns a row, not merely that some manifest has the name: the driver
PRINTS a regeneration command and `check-regen-pending.mjs` SPAWNS one, and both
were bound to `packages/spec`. A root-owned row under a widened lookup would
have reconciled green and then been spawned in a directory that does not define
its script — measured, `pnpm -s check:sdui-lockstep` exits 254 there and 0 at
the repo root — leaving the artifact permanently stale and every commit refused.
Registered-and-unreconcilable is a worse defect than unregisterable.
`reconcileOwnership()` pins the rule against the real root manifest on every
run, including the case a permissive lookup would fail: a root-only script name
must NOT resolve under @objectstack/spec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate
2 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#13585
git-merge-regen.mjs --self-testresolved every regen row'sgen:/check:names inpackages/spec/package.jsonand nowhere else, so an artifact owned by root tooling could not beregistered for
merge=os-regenat all — however exactly it matched the pathology the driver existsfor. The refusal was correct about the tree and wrong about the world: it read as "you named a
script that does not exist" when the truth was "this artifact is not owned by
packages/spec."Rows now carry an
owner, defaulting to@objectstack/spec— which is what all 13 existing rowsdeclared implicitly — and the refusal names the manifests it searched.
Verified on
1997df337.必答項 — is
check:merge-driver's reconciliation still two-way?Yes, and that requirement is what chose the shape of the fix. The answer has two halves.
1. The lookup stayed exact, so nothing became merely permissive
A name is looked for in one manifest — the row's declared owner's — never in "any manifest that
happens to have it". A widened lookup would have made resolution non-deterministic the moment two
manifests defined the same
gen:name, and would have accepted a row that names a root-only scriptwhile claiming a package owner. It is pinned as a live case rather than argued:
reconcileOwnership()asserts thatcheck:merge-driver, a root-only script name, resolvesunder
ROOT_OWNERand does not resolve under@objectstack/spec. A permissive lookup passesevery other assertion in that block and fails exactly that one.
Both directions of the
.gitattributes↔ table reconciliation are untouched, and an owner thatresolves to no manifest is a refusal, not a skip — an unresolvable owner means a row whose
scripts were never verified, which is the state this reconciliation exists to make impossible.
2. The half that a one-sided loosening would have left standing — measured, not reasoned
This is the "registered but unreconcilable" seam, and it was real. Two consumers need to know
which manifest owns a row, not merely that some manifest has the name:
git-merge-regen.mjsprints a regeneration command at merge time;check-regen-pending.mjs(thepre-commitgate) spawns one.Both were bound to
packages/spec— the runner's spawn directory waspackages/specunconditionally. Measured before the
ownerfield existed:So a lookup-only widening would have produced a row that reconciles green and is then
permanently unsatisfiable in the hook. Driven end to end against the real
check-regen-pending.mjs, same root-owned row, the only difference being theownerdeclaration:A — root-owned row, no
ownerdeclared (what a lookup-only widening leaves behind):Every commit refused, forever, with remedy advice that cannot work.
B — the same row declaring
owner: ROOT_OWNER(this PR):That is why the owner is declared rather than searched for: one declaration, read by the gate,
the driver's advice and the hook's spawn, so the command the driver prints is the command the gate
runs. Registered-and-unreconcilable is a worse defect than unregisterable, and a widened lookup
alone would have manufactured it.
Non-empty control — rejected before, registered after
The artifact that produced the finding,
docs/audits/2026-08-tenant-audit-write-call-sites.counts.md,lives on PR #13584's branch and is not on
main, so it could not be used. The control used insteadis
packages/sdui-parser/objectui-lockstep.jsonwithgen:sdui-lockstep/check:sdui-lockstep— the only root-owned
gen:/check:pair in the root manifest onmain, i.e. a genuinelyroot-owned artifact and not a
packages/specentry testing a path that already worked.Before the fix (registration attempted on
origin/main, then backed out) — the card's exactrefusal shape, reproduced on a different artifact:
After the fix, same row, still no
owner— still refused, because the loosening is not blanket,and the refusal now names what it searched and points at the right repair:
After the fix, declaring
owner: ROOT_OWNER— registers, andpnpm check:merge-driveris greenend to end (exit 0):
And a third leg, an owner nobody can resolve refuses rather than skipping:
All three registrations were temporary, applied on top of the committed implementation and backed
out with
git checkout HEAD -- ...; restoration was proven by an emptygit diff HEADplus aHEAD-blob-hash comparison per file, not by an exit code.
Why the control artifact is not registered permanently here
packages/sdui-parser/objectui-lockstep.jsoncan now be registered, and deliberately is not.gen:sdui-lockstepre-reads objectui's side, which needs an objectui checkout the merger is notholding — so the deferred regeneration would be unrunnable at exactly the moment
pre-commitdemandsit, and the driver only ever defers. Its conflict is also not the shape the driver exists for: the
record holds one side at a named revision, so two branches that each re-recorded it disagree
about which objectui revision the parity was verified against, and no regeneration answers that.
Registering it to give this PR a permanent control would be the test dictating the code, so the
durable guard is
reconcileOwnership()instead — it reads the real root manifest through the samefunctions the driver and the hook use, on every
check:merge-driverrun.The refusal now names which manifests were searched
Per the card: a refusal that misdescribes its own cause sends the reader to the wrong repair. The new
text names the owner and manifest per dead row, lists every manifest searched, states that an
undeclared row defaults to
@objectstack/spec, and explicitly refuses the repair the old textimplied — moving root tooling into a package to satisfy a lookup path.
PM mechanism assumptions — verified
"All currently-registered paths are spec-owned or spec-adjacent; the single-manifest assumption
has never been stressed."Confirmed, with a correction to the count. There are 13
registered paths on
main, not 14 (the card's14was measured with its own candidate rowalready added). Ten are under
packages/spec/; the other three —docs/protocol-upgrade-guide.md,docs/audits/2026-07-unknown-key-strictness-ledger.counts.mdand
content/docs/references/**— are outsidepackages/. All 13 name scripts defined inpackages/spec/package.json, so the assumption held by coincidence of ownership, never byconstraint.
"
docs/protocol-upgrade-guide.mdis outsidepackages/with only its scripts inside — the realboundary is the manifest, not the artifact path."Confirmed, and stronger than stated: it is
one of three such rows, not one. The boundary was always the manifest.
"The two-way reconciliation is the fragile half; if loosening it cleanly is impossible without a
declared-owner field, say so."Confirmed, and that is the shape delivered. A widened lookup
cannot supply what the driver's advice and the hook's spawn need — which package — so the
declared-owner field is not one of two acceptable options here but the only one that keeps the
reconciliation two-way. See the 必答項 section.
On #13335
Triage's grading placed #13335 as the symptom of this cause, with this card blocking it. That
blocking relationship does not hold, and the acceptance case could not be run as specified.
skills/*/references/_index.mdis written bygen:skill-refsand gated bycheck:skill-refs, andboth of those are defined in
packages/spec/package.json(lines 257-258), not in the rootmanifest:
So that artifact was never blocked by the single-manifest lookup — it is spec-owned and could
have been registered at any time. Registering it here would therefore have been the vacuous control
this lane rejects: a
packages/specentry exercising a path that already worked. It is also adisposition question in its own right (route it, or record why it must keep text-merging), which is
the substance of that card and not of this one. #13335 stays open and untouched; nothing under
skills/**is in this diff. The card's own body hedged this correctly — "If that card's generatoris also root-owned, this one blocks it" — and it is not.
Verification
Gate family derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(15 families + 2 convention-triggered for editing a gate script), not guessed. All run at
1997df337:check:merge-driver— green, including the new✓ owner resolution: 11 case(s) pinnedlinecheck:agent-test-spelling,check:bash32-floor,check:cli-command-ids,check:cross-package-test-inputs,check:entry-guard,check:parse-guard,check:pnpm-filter-targets,check:watch-hint-literal— greencheck-ci-filter-parity.mjs,check-cross-package-test-inputs.mjs,check-shard-attestation.mjs— greenbare-root-worklist.mjs --self-test,check:pm-dispatch-gates(the two gate-script conventions) — green@objectstack/speccheck:generated(all 14 generated artifacts up to date) andcheck:docs(230 generated files in sync) — green, after a full spec build
pnpm lint— the whole repo,eslint . --no-inline-config, green. No narrowing claimed.check:nul-bytes— green; the diff also self-scanned for raw control bytes, nonecheck-declaration-mirrors.mjs(the.d.mtsmirror of the edited runner) — greendist-freshness.test.ts,schema-tree-freshness.test.ts,build-schemas-check-mode.test.ts— 3 files, 84 tests passed —plus
check:scripts-typecheck— greencheck-test-completeness.mjs— NOT MEASURED, by the gate's own declaration: it grades a savedturbo run testlog and exits 3 (PREREQUISITE NOT MET) when run without one, which is the shapethe derived family invokes. Not a red.
No changeset: this PR releases nothing from any package — the diff is three root tooling scripts —
so it carries
skip-changeset.Generated by Claude Code