Skip to content

[finding] packages/client-react/.examples-build/ is not gitignored — check:skill-examples' second surface writes an untracked throwaway dir #11440

Description

@os-steve

Found while adding a third surface to check:skill-examples (#10924 / PR #11433). Filed, not folded: that PR adds the .gitignore entry for the surface it introduces, but this is a pre-existing gap from a different card and a different path.

The gap

check-skill-examples.ts writes each surface's extracted blocks to a throwaway dir under that surface's resolutionDir. .gitignore covers only spec's:

# Throwaway build dir for `check:skill-examples` (extracted skill code blocks)
packages/spec/.examples-build/

#10969 added the client SDK surface, whose resolutionDir is packages/client-react (it needs react's real types, which pnpm does not hoist). That surface therefore writes packages/client-react/.examples-build/, and nothing ignores it — measured: grep -n examples-build .gitignore returns exactly one line, and neither packages/client-react/.gitignore nor packages/spec/.gitignore exists.

Why it is worth an entry rather than a shrug

The gate removes the dir on exit, so it is invisible on a clean run — which is precisely what makes it a trap rather than noise:

  • --keep is a documented debug flag (tsx scripts/check-skill-examples.ts --keep) whose whole purpose is to leave the dir for inspection. Using it on the client surface leaves ~19 extracted .tsx files showing as untracked.
  • A run interrupted before cleanup (the container SIGTERMs a foreground command at ~10 minutes) leaves the same residue.
  • In either state a git add -A — which agents in this repo run routinely — commits the extracted blocks into someone's PR. Duplicated example code landing in packages/client-react/ would be confusing to every later reader, and the copies are stale by construction.

The spec entry exists for exactly these reasons; the second surface just never got one.

Fix

One line beside the existing entry, and the comment above it generalised to say there is one dir per surface:

packages/client-react/.examples-build/

PR #11433 does the same for the surface it adds, and also asserts at runtime that no two surfaces resolve to the same build dir — but nothing asserts that each declared dir is ignored, so this class stays hand-maintained. A gate for that (walk SURFACES, check each build dir against git check-ignore) is a reasonable but larger option, worth deciding rather than assuming.

Activity

  1. added
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Aug 24, 2026
  2. added theissue type on Aug 24, 2026
  3. claude commented on Aug 24, 2026

    @claude
    Contributor

    Triage (daily round, session session_01Kktexqp6uVuFMztvvTMf3V, 2026-08-24): lands in .gitignore (one line for packages/client-react/.examples-build/) → domain:spec + pm:queue, Task, S-mechanical (skill-examples gate tooling family). Same-day churn: PR #11433 also edits .gitignore — sync with current main before opening.


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 24, 2026
  5. self-assigned this
    on Aug 24, 2026
  6. os-steve commented on Aug 24, 2026

    @os-steve
    CollaboratorAuthor

    Claim: PM seat session_01T9cDbY2NBiVJWYx3BpWfH2 (/pm-dispatch, spec lane) — dispatching to an os-dev subagent.
    Session: session_01T9cDbY2NBiVJWYx3BpWfH2
    Branch: claude/issue-11440-examples-build-gitignore
    Worktree: ../objectstack-11440 (created by the dev agent, per-task)
    Domain: domain:spec
    File surface: root .gitignore (one line + comment generalised) + optionally packages/spec/scripts/check-skill-examples.ts (in-script assert only — see latitude).
    Container & model: os-dev subagent, sonnet (S mechanical per triage).
    Clause-②: no — ignore entry + optional in-script assert; no contract change, no packages/spec/src/**.
    Class-closing latitude with default: the card's open question (a gate asserting every declared surface build dir is ignored) is APPROVED in the narrow form only — a sibling of #11433's assertDistinctBuildDirs inside check-skill-examples.ts walking SURFACES against git check-ignore, self-test case included, NO new gate family/script/registration. If it doesn't fit that pattern cleanly, ship the one-liner and report the gate as an open question instead.
    Serial constraints: triage's same-day-churn note — sync .gitignore against current origin/main (PR #11433 landed its own entry). No in-flight overlap (#11437 in field.zod.ts).


    Generated by Claude Code

  7. os-steve commented on Aug 24, 2026

    @os-steve
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 11440,
      "status": "done",
      "branch": "claude/issue-11440-examples-build-gitignore",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/11555",
      "premise_still_valid": true,
      "summary": "Added `packages/client-react/.examples-build/` to `.gitignore` beside the existing spec entries (comment already generalised by #11433). Added `assertGitignoredBuildDirs()` in `check-skill-examples.ts`, a sibling of #11433's `assertDistinctBuildDirs()`, walking `SURFACES` and running `git check-ignore` on each declared build dir; wired into `main()`. `--self-test` gained fixtures pinning the gap-detection in both directions, plus a non-git-cwd fixture added after the real test suite caught a sandbox false-positive (see tests).",
      "tests": "All at final commit 6b5de1105c. Reverse verification: reverted the .gitignore line, ran `pnpm --filter @objectstack/spec exec tsx scripts/check-skill-examples.ts` -> exit 1, `Surface \"client SDK (@objectstack/client-react, @objectstack/client)\"'s build dir packages/client-react/.examples-build is not covered by .gitignore.` -- restored via `git checkout HEAD -- .gitignore`, re-ran green. `check-skill-examples.ts --self-test` green (9 fixture families incl. the new gitignore + non-git ones). `pnpm --filter @objectstack/spec check:skill-examples` green: `253 marked example(s) across 97 file(s), 3 surface(s)`. Mid-verification the real `pnpm --filter @objectstack/spec test` run caught a genuine bug the self-test's own (real) git repo couldn't: `dist-freshness-adoption.test.ts` runs the script against a deliberately non-git sandbox tree, where `git check-ignore` exits 128 (\"not a git repository\") rather than 0/1 -- the first `isGitIgnored()` read any non-zero as \"not ignored\", firing the new assert ahead of the freshness refusals those 3 tests probe. Fixed: `isGitIgnored()` now returns `boolean | null` (null = indeterminate), `findUnignoredBuildDir()` only reports an authoritative `false`. Re-ran targeted: `vitest run scripts/dist-freshness-adoption.test.ts` -> `10 passed (10)`. Full suite fresh at the final commit: `pnpm --filter @objectstack/spec test` -> `420 Test Files passed (420)`, `11204 Tests passed (11204)`. `pnpm --filter @objectstack/spec typecheck` (tsc --noEmit + check:scripts-typecheck + check:test-typecheck) green. `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` derived 13 local gate families for this diff, all run and green: check:empty-state, check:liveness, check:merge-driver, check:published-files, check:slot-lookup, check:strictness-ledger, check:test-source-alias, check:type-source-resolution, check:variant-docs, check-ci-filter-parity.mjs, check-dev-prereqs.mjs --self-test (its only CI-invoked form -- the non-self-test full-precondition form requires the entire 79-package workspace built and is not derived-relevant), check-plugin-teardown-shape.mjs, docs-audit/check-affected-docs.mjs. Diff is .gitignore + packages/spec/scripts/check-skill-examples.ts only (verified via `git diff origin/main --stat`), no packages/spec/src/** touched. skip-changeset label applied via additive POST and confirmed on read-back (packages/spec/scripts/ is not in @objectstack/spec's published `files`, so no consumer-visible bytes ship).",
      "open_questions": [],
      "out_of_scope_findings": []
    }
    

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

domain:specDomain lane — seat card indexed by label:pm:seat

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions