Skip to content

check:docs-audit-scope (affected-docs --self-test) answers a finding's exit 1 on an unbuilt workspace — the contract-declaration case flips with the build state, where its siblings exit 3 PREREQUISITE NOT MET #15328

Description

@os-justin

Found while running the derived gate list for PR #15284 on a fresh worktree (head 49f19218b, merged past e77635b8f); filed unassigned, out of that PR's scope. Same class as #15285 (a gate reporting an unbuilt workspace as findings, exit 1, where its sibling exits 3) — a different gate, so a separate card.

What was observed

pnpm check:docs-audit-scope = node scripts/docs-audit/affected-docs.mjs --self-test && …. On a worktree where @objectstack/spec was built but the rest of the workspace closure was not (no packages/lint/dist, no packages/client-react/dist, …), the self-test failed with exit 1:

  ✗ self-test "every contract declaration admitted is a packages/spec API declaration": kind=contract → expected scanRouteSurface=true, got false
✗ affected-docs self-test failed (1 case(s)).

After pnpm exec turbo run build --filter=@objectstack/client-react --filter=@objectstack/lint (34 tasks) the SAME command, on the SAME tree (no file changed, git status clean), passed: node scripts/docs-audit/affected-docs.mjs --self-test exit 0, pnpm check:docs-audit-scope exit 0 ("✓ scope injection is live …").

The case is the one e77635b8f (#15274, "a route SOURCE of two kinds — admit spec contract declarations behind a runtime-registration guard") added at scripts/docs-audit/affected-docs.mjs:5568: liveKind('contract').every((f) => f.startsWith('packages/spec/src/api/')). Its answer depends on what the runtime-registration guard can see, and on an unbuilt closure the guard admits at least one contract declaration outside packages/spec/src/api/. The branch under test touches 0 lines under scripts/ (git diff --stat origin/main HEAD -- scripts/ empty), so this is the gate's own behaviour, not the PR's.

Why it matters

The repo's convention for "this gate reads built output and it is not there" is exit 3, PREREQUISITE NOT MET (check:type-check-debt, check:dual-build-cjs-loads, check:doc-security-posture, check:doc-formula-expressions all answer that way on the same unbuilt tree). Exit 1 here reads as a red finding: a dev re-deriving gates on a fresh worktree gets a false red they cannot distinguish from a real self-test regression, and a CI job that happened to run it before the closure build would be red for the same non-reason. The two readings (unbuilt → 1, built → 0) are the false-green/false-red pair the exit-3 convention exists to separate.

Repro

git worktree add ../objectstack-probe origin/main && cd ../objectstack-probe && pnpm install
pnpm --filter @objectstack/spec build                      # spec only
node scripts/docs-audit/affected-docs.mjs --self-test > /tmp/a.log 2>&1; echo "EXIT=$?"   # 1, the kind=contract case
pnpm exec turbo run build --filter=@objectstack/client-react --filter=@objectstack/lint --concurrency=2
node scripts/docs-audit/affected-docs.mjs --self-test > /tmp/b.log 2>&1; echo "EXIT=$?"   # 0

Suggested direction (not decided here)

Either the runtime-registration guard detects the unbuilt prerequisite and the self-test exits 3 with the PREREQUISITE NOT MET wording its siblings print (naming the missing dist), or the kind=contract case is made independent of built output (read the declarations from source). Which of the two is the #15274 author's call.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions