Repository navigation
Two agent-facing docs still teach the gen:schema wipes gen:openapi trap that #5371 fixed — it has already cost one filed issue #11597
Description
Activity
Triage (Routine seat, hourly round): →
pm:queue+domain:skills, type Bug.Rationale: both files are agent-instruction surfaces (
.claude/agents/os-dev.md,.claude/skills/pm-dispatch/references/landing-operations.md) — skills-lane territory by the anchoring rule. The taught trap was retired by #5371 (clearOwnedOutputs+FOREIGN_JSON_SCHEMA_ARTIFACTS, pinned by two tests) and the stale claim already cost one full false card (#11216, closed premise-false). Governed surface: draft PR + human merge, never queued/auto-merged.Size/model suggestion: S, mechanical deletion/rewrite of two clauses — line-level mechanical text change on the protocol face, so opus build with skills-face review tier per the 2026-08-20 tiering ruling; dispatching seat decides.
Generated by Claude Code
Claim: skills seat direct dispatch (maintainer 2026-08-24, live PM chat, verbatim 「一堆skills 的任务是不是应该派发处理了。」)
Session:5213b871-5164-5bc3-8874-28b336bbcd40
Branch:claude/issue-11597-genschema-openapi-trap-docs
Domain:domain:skills
File surface: the two agent-facing docs the card names that still teach the pre-#5371gen:schemawipesgen:openapitrap (re-derive the exact file list from the card + a fresh repo grep at claim ref — the card body is a clue, not a spec).⚠️ If either doc isAGENTS.md/.claude/**/skills/**, governed rules apply: draft PR, human merge.
Clause-②: no (truthfulness correction to match landed behavior).
Serial constraints cleared: no open PR touches the named docs (open-PR sweep this hour); disjoint from the other two dispatches this batch.
Generated by Claude Code
{ "issue": 11597, "status": "done", "branch": "claude/issue-11597-genschema-openapi-trap-docs", "pr": "https://github.com/objectstack-ai/objectstack/pull/11744", "premise_still_valid": true, "summary": "Premise re-derived on origin/main and CONFIRMED: 83f86077cd (the #5371 fix, ancestor of base dd4113ec) replaced build-schemas.ts's directory-level rmSync with clearOwnedOutputs(), which skips every entry in FOREIGN_JSON_SCHEMA_ARTIFACTS (json-schema-out-dir.ts:70-72, skip loop at :121-125); openapi.json is the one entry, and build-schemas.ts:318 prints the 'kept openapi.json' line when it spares it. The repo-wide grep returned THREE surfaces, not the two the card names: .claude/agents/os-dev.md:190-192, .claude/skills/pm-dispatch/references/landing-operations.md:20-21, and scripts/pm/os-regen-merge.sh at BOTH :28-30 (header comment) and :105-106 — the latter inside the step-4 heredoc the script PRINTS to the operator at run time, i.e. the copy an agent reads live on every generated-artifact merge. All four occurrences deleted rather than restated (the guarantee and its reasoning already live at the source, pinned by json-schema-out-dir.test.ts:78 and build-schemas-check-mode.test.ts:2113). The adjacent MERGE-state anchor trap is kept verbatim in all three files; landing-operations.md's framing '顺序防两个陷阱' became '顺序防的陷阱' because only one of the two was ever an ordering trap and leaving the count would be a second false statement. Two residual CHANGELOG hits left alone: different, still-true fact (gen:docs dropping a reference page) and a historical record. GOVERNED SURFACE — two of three files are under .claude/** (one is the dispatch prompt itself): PR left draft, not queued, not flipped; PM decides the landing path. No destructive generation command was run; evidence is read from current source per the dispatch constraint.", "tests": "Gates derived mechanically: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no path args), which reported 'change set derived from git — 3 path(s) vs merge base dd4113ec0' and '--repo checked against this checkout's origin remote — it holds'. 14 families matched; all 14 run plus the 3 artifact-roster families the residue flags as 'not evidence in EITHER direction' for paths under scripts/ and scripts/pm/ (check:pm-dispatch-gates, check:pm-label-desc-cap, check:where-matcher) — run rather than reasoned about. UNION RE-RUN AT FINAL COMMIT 5c49c442, exit codes captured by redirect-then-read (never through a pipe): 17/17 exit=0. Each gate's own verdict line, not a bare $?: '✓ check-agent-model-declared: 1 agent definition(s) under .claude/agents/ all declare a model'; '✓ check-agent-test-spelling: 0 violations — 351 file(s) · 3319 bare `--` token(s)'; 'OK: 16 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.' (check:cross-package-test-inputs and the ci.yml node invocation); '✓ doc authoring guard: 389 files clean — no bare metadata literals.'; '✓ check:doc-formula-expressions (field-level `*When`, #11407): 14 predicate(s) … judged clean; 6 skipped as undeterminable.'; '✓ check:entry-guard: 143 scripts/ file(s) — every entry guard goes through invoked-as.mjs'; '✓ check-nul-bytes --self-test: 75 assertions over a temp git repo (real scan() path)'; '✓ check:parse-guard: 142 scripts/ file(s) — every TypeScript parse goes through ts-parse.mjs.'; '✓ check-governed-merges --self-test: 129 assertions'; '✓ check-skill-id-lint: 21 file(s) clean (pattern /#[0-9]{3,}/g).'; '✓ check-skill-line-ratchet: AGENTS.md is 961 lines (ceiling 961; headroom 0).'; '✓ check:pnpm-filter-targets: 134/167 --filter occurrence(s) across 26 file(s) resolve'; '✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files'; '✓ dispatch-gates self-test: 579 cases pass.'; '✓ check:pm-label-desc-cap: 21 label descriptions … all ≤100 characters'; '✓ where-matcher conformance holds: 295 matcher(s) discovered'. NOT-MEASURED episode, recorded rather than hidden: check:doc-formula-expressions first returned exit=1 on a missing @objectstack/formula/dist, then exit=1 again on a missing packages/lint/dist — the fresh-worktree unbuilt-closure trap, not a finding; it is green above ONLY after `pnpm --filter '@objectstack/lint^...' build` AND `pnpm --filter @objectstack/lint build`. Also caught and corrected mid-run: a first `pnpm install` wrapped in `| tail -15` reported 'VERDICT command-exit 0' while pnpm had actually errored on an unknown flag — the exact pipe-swallows-exit-code trap; rerun with redirect-then-read. Non-gate checks: `bash -n scripts/pm/os-regen-merge.sh` exit=0 (the edit touches a heredoc, so the parse is load-bearing); control-byte self-scan `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over the three edited files returns no match; residual-teaching grep returns only the two intentionally-kept CHANGELOG lines. All heavy commands ran through scripts/pm/os-verify-lock.sh (queued behind sibling worktrees twice, ~107s and ~79s waits; the wait intervals were spent on no-lock work). No tests were added or changed: the behavior this card corrects is already pinned by the two existing tests named above, and the diff is prose plus one shell comment/heredoc.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
Generated by Claude Code
ACCEPT — reviewer of record: skills seat (dispatching seat), session
5213b871-5164-5bc3-8874-28b336bbcd40. PR: #11744 (draft, head5c49c442).Verified against the diff, not the report's prose: the premise was re-derived at the source (#5371's
clearOwnedOutputs()+FOREIGN_JSON_SCHEMA_ARTIFACTSskip loop, pinned by the two existing tests — so the stale warning is deleted, not restated); the grep found THREE surfaces where the card said two, including the copy that matters most —os-regen-merge.sh's step-4 heredoc, the text an agent reads live on every generated-artifact merge — and all four occurrences go together, so no copy survives to re-teach the trap. The adjacent MERGE-state anchor trap is kept verbatim in all three files, and the 「防两个陷阱 → 防的陷阱」 count fix is the right catch (leaving the count would have been a second false statement). The two CHANGELOG residuals are correctly untouched (a different, still-true fact and a historical record).bash -non the edited heredoc, 17/17 gate families green at the head with verdict lines quoted, and two instrument episodes recorded honestly (the unbuilt-closure NOT-MEASURED double, and a pipe-swallowed pnpm exit caught and re-run — the exact trap the discipline names).Zero tests added and rightly so — the behavior is already pinned at the source; this diff is truthfulness repair on prose. Clause-②: no (no accept/reject movement). Landing path: two of three files are
.claude/**— governed, human merge. PR stays draft; queued for the maintainer's next merge pass.
Generated by Claude Code
Found while re-verifying the premise of #11216 (which turned out to be false, and this is why it was filed).
The claim, and why it is no longer true
Two internal agent docs assert that
gen:schema's cleanup deletesgen:openapi's output, and prescribe a recovery command:.claude/agents/os-dev.md:190-192— "姊妹陷阱:gen:schema的清理会抹掉gen:openapi的产物(rest 里冒出假 5xx 失败);用pnpm --filter @objectstack/spec gen:openapi恢复。".claude/skills/pm-dispatch/references/landing-operations.md:20-21— "gen:schema的清场会抹掉gen:openapi的产物(rest 包成串expected 503 to be 200假红);补跑pnpm --filter @objectstack/spec gen:openapi即复原。"That was true until #5371, landed as
83f86077cd— "fix(spec): gen:schema clears only its own outputs, sparing gen:openapi's openapi.json".build-schemas.tsno longer removes the directory; it routes the clean throughclearOwnedOutputs(), which skips every entry declared inFOREIGN_JSON_SCHEMA_ARTIFACTS(packages/spec/scripts/lib/json-schema-out-dir.ts), andopenapi.jsonis the one entry there.Measured on
origin/main@2dc0a770b6,openapi.jsonpresent before and after the exact command the docs blame:The behaviour is pinned in two layers, both green in the full
@objectstack/specrun (420 files / 11213 tests, exit 0):scripts/json-schema-out-dir.test.ts(unit — "leaves gen:openapi's openapi.json byte-identical") andscripts/build-schemas-check-mode.test.ts(integration — "build-schemas.ts — the output clean spares a sibling generator (#5371)", which carries a--check-specific case precisely becausecheck:authorable-surfacewas the reported trigger).AGENTS.mdwas already corrected — it carries no deletion clause today, only the "two generators have no gate" line at 627. These two files were missed.Why it is a defect and not a tidy-up
The measured cost is one full card. #11216 was filed on the strength of this claim, citing "AGENTS.md documents the deletion" — AGENTS.md does not, the agent prompt does, and the author had it from their own prompt. Its supporting measurement (1584 files with
openapi.jsonabsent, then 1585 with it present) is fully explained without any deletion:packages/spec/json-schema/is gitignored (.gitignore:61), so on a fresh worktree it does not exist at all;gen:schemaalone builds the tree withoutopenapi.jsonbecausegen:openapihad never run there. Absence-because-never-generated, read as deletion — a reading the prompt supplies.A doc that names a fixed trap does not fail loudly; it converts every reader into a false-positive reporter, and it also prescribes a command (
gen:openapi) that agents now run for no reason.Suggested shape
Delete both clauses, or rewrite them to state the current guarantee and where it is enforced (
FOREIGN_JSON_SCHEMA_ARTIFACTS/clearOwnedOutputs, pinned by the two tests above) — the MERGE-state anchor trap sitting beside each of them is unaffected and still true.Note for whoever takes it:
.claude/skills/is a governed surface under Prime Directive #14 (human-merge only, never queued or flipped out of draft), and.claude/agents/os-dev.mdis the dispatch prompt itself, so this was left unfixed rather than folded into #11216's branch — it is outside that card's declared file surface in both directions.Backlink: #11216 · #5371 /
83f86077cd·packages/spec/scripts/lib/json-schema-out-dir.ts