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
{{ message }}
Repository navigation
finding(create-plugin): every scaffolded source file carries an "ObjectStack Inc." copyright header for the author's own code #8778
Found while implementing objectui#8041 (the licence-text card), in the same file and a line away from the line that card moves. Deliberately not changed there: objectui#8041's dispatch holds every emitted file, prompt and manifest field outside the licence question constant, and the right value for this line is a product decision rather than a mechanical substitution.
What the generator emits.packages/create-plugin/src/templates.ts — buildIndexFile, buildImplFile, buildTypesFile and buildTestFile each open the file they write with this block (the year interpolated from new Date().getFullYear()):
/**
* ObjectUI
* Copyright (c) 2026-present ObjectStack Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Measured on c03d03bb2 by running the real scaffolder (built dist/index.js, driven through a pty with default answers) into a scratch directory: all four emitted src/* files carry it verbatim. Unchanged on a04441f, the objectui#8041 branch head, apart from the licence NAME on the fifth line.
Why this is a defect and not a style nit. Those four files are the author's own plugin code — the component implementation, its schema types, the package entry and its example test. The notice names a third party (this project) as the copyright holder of code the author has not written yet, in a package the author will publish under their own name. It is a stronger claim than the one objectui#8041 was about: that card's manifest asserted a licence choice on the author's behalf; this line asserts ownership.
The rest of that header block is now true. After objectui#8041 the LICENSE file it points at really is emitted, and the licence it names follows what the author chose. The copyright line is the one statement in the block that is still false, and it is now the only one.
Needs triage, not a guess — the candidates point in different directions.
Drop the block from the four emitted sources entirely. Simplest, and a scaffolded file needs no header.
Keep it and name the author (vars.author). But the author prompt is optional with an empty initial, so this needs an answer for the blank case — the same question objectui#8041 had to answer for the LICENSE copyright line.
Replace the copyright claim with a provenance line that is not one — e.g. a "generated by @object-ui/create-plugin" comment. It is the only candidate that says something true without adding a prompt, but whether a generated file should carry provenance at all is a product call.
Related and deliberately separate: objectui#8041 (same file, licence half, ruled and shipping), objectui#3647 (the in-repo instance of the licence-text shape).
Filed by the objectui#8041 development seat under the out-of-scope-finding rule; no assignee, no labels — triage owns both.
Triage: lands in packages/create-plugin/src/templates.ts; domain:ui; priority:p2. The removal is ruled; ⛔ the replacement text is NOT.
buildIndexFile / buildImplFile / buildTypesFile / buildTestFile each open the file they emit with an "ObjectStack Inc." copyright header — on the plugin author's own code. ⇒ our scaffolder writes our company's ownership claim into files the user wrote, and the user has no reason to look at line 1 of a generated file.
What is ruled, and what is fenced
✅ Ruled: stop emitting that claim. Asserting this project's copyright over a third party's source is a factual defect, not a style preference, and correcting a false statement the tool emits is squarely dispatchable.
⛔ Not ruled, and ⛔ not to be decided by the implementer: what replaces it. Any substitute is a legal assertion about the author's code — a placeholder, an SPDX line, the author's name from the manifest, or nothing at all. ⇒ the safe landing is to emit no copyright header, which asserts nothing. If you believe a specific legal string belongs there, stop and report rather than choosing one; that is a maintainer question.
⚠️ Related, ⛔ separate: objectui#8892 is the buildLicenseFile MIT-fallback disagreement in the same file. ⇒ hot file, serial, and ⛔ do not fold — one is a copyright header on emitted source, the other is manifest/LICENSE parity.
⛔ Not in scope: objectui#8041's licence-text question, whose dispatch held every emitted file, prompt and manifest field constant.
os-dev-report
{
"issue": 8778,
"status": "done",
"branch": "claude/issue-8778-scaffold-copyright-header",
"pr": "#9008",
"premise_still_valid": true,
"summary": "Removed this project's copyright claim from every source file the scaffolder writes for the plugin author, and put NOTHING in its place — the safe landing triage named. Deleted from all four emitted-source builders (buildIndexFile, buildImplFile, buildTypesFile, buildTestFile) in packages/create-plugin/src/templates.ts: the 'Copyright (c) YEAR-present ObjectStack Inc.' line, the 'ObjectUI' title line above it, and the blank comment line between them — 12 lines, no substitute chosen. JUDGMENT MADE, and reversible: I removed the title line as well as the copyright line. It is not a legal claim, but it stamps this project's name on the author's source, and deleting it asserts nothing, so it moves toward the ruling rather than past it. If the maintainer wants that line kept, restoring it is a one-line change and reddens only the header pin. The licence pointer sentence was KEPT, deliberately: verifying the brief's second assumption showed it is the one statement in the block that is true, and it is load-bearing — it is one of the six agreeing licence statements objectui#8041 and objectui#8892 built, and two landed tests read it. Deleting the whole block would have dropped four of those six and reddened both. Added one note above the four builders recording that the absence is deliberate and that nothing may replace it without a maintainer decision. No prompt, no manifest field and no other emitted file changed. No maintainer question needed answering, so this is not a needs_decision.",
"emitting_functions": "Exactly four, and the brief's assumption is CONFIRMED: buildIndexFile, buildImplFile, buildTypesFile, buildTestFile — all in packages/create-plugin/src/templates.ts, contiguous. No fifth emitter and no variant: a whole-repo sweep for the interpolated form returns those four only. The other Copyright strings this package produces are the licence TEXTS in src/licenses.ts, whose holder is the author via licenseCopyrightHolder (objectui#8041 / objectui#8892 territory, correct). The three literal headers in templates.ts, licenses.ts and index.ts are this repo's OWN source and are untouched. Docs reproduce none of it: zero occurrences of 'Copyright' anywhere under content/, and the create-plugin page deliberately does not reproduce the generated tree.",
"rest_of_block_true": "YES — verified, and it changed the shape of the fix rather than merely confirming a guess. The remaining sentence is true on every clause: buildPluginFiles really does emit the LICENSE beside those four files; the id is the licence the author chose at the prompt (objectui#8041); and buildLicenseFile refuses an id it has no text for (objectui#8892), so it cannot name a licence the package does not carry. There is no second false statement. Because of that the brief's trade-off resolves toward deleting only the ownership lines: the sentence is one of the six agreeing licence statements those two closed cards built, and deleting the whole block reddens licenses.test.ts 'names one licence, not two' and the objectui#8892 six-way agreement case. One clause is ambiguous rather than false and is left alone: 'the root directory of this source tree' is true when the source tree is the generated package (LICENSE sits at its root), which is the reading buildPluginFiles produces; it is not true of the monorepo the scaffolder writes into.",
"removed_and_left": "REMOVED, 4 sites x 3 lines: the copyright line, the ObjectUI title line, the blank separator. LEFT: the licence pointer sentence alone, wrapped in the block comment, with the id following the author's choice. ADDED: a note above the four builders, and a patch changeset.",
"tests": "type-check (create-plugin, both projects incl. the test tsconfig): exit 0. Package suite from the repo root (pnpm exec vitest run packages/create-plugin/): exit 0, 3 files / 40 tests passed. Package lint as turbo runs it: exit 0. END-TO-END ACCEPTANCE, the way this card was originally measured and objectui#8892 was accepted: the built bin driven through a pty with answers into a scratch dir, then the four emitted src files read off disk. Two new cases in cli-cancel-and-nontty-8786.test.ts — which is where they MUST live, since a second test file building this package would clean dist/ out from under the runs already there. Case 1 asserts no ownership claim in any spelling (Copyright, (c), the copyright sign, ObjectStack, ObjectUI, SPDX, All rights reserved) and not the author's answered name either; the author is answered as 'Ada' so the fenced substitution has a value it could have been made from. Case 2 pins the leading comment VERBATIM against the id read back off the manifest, because 'no copyright header' and 'no header' are different landings. Both anti-false-green controls are asserted: the ten-file list is pinned BEFORE any absence is read, and the same run's LICENSE is required to carry the very copyright line these four must not. ABLATION — prediction stated before running: exactly the 2 new cases redden, the 8 pre-existing cases in that file stay green. MEASURED: mutate leg rewrote 4 sites, grep -c on disk = 4, blob hash moved off the HEAD blob; the rebuilt dist/index.js carried the marker 4 times, proving the mutation reached the bin the tests actually drive; run exit 1 with 2 failed / 8 passed — exactly as predicted, both failures quoting the real restored header. Restore leg: git checkout HEAD on the path, blob hash back to the HEAD blob, git diff HEAD empty, re-run exit 0, dist marker count back to 0. Trap-guarded restore with absolute paths throughout. The reddening also settles what a passing count alone could not: those two cases really ran and really witnessed the bytes.",
"gates": "type-check 0 | create-plugin suite (from root) 0 | package lint 0 | check:control-bytes 0 (plus a manual sweep of both edited files) | check:changeset-presence 0 | check:governed-queue-guard --test 0 (NOT GOVERNED: 3 paths, 0 matched) | check:new-line-citations 0 | check:doc-snippets 0 (638/638 blocks judged, 0 failed) | check:doc-types 0 | check:doc-examples 0 (124 blocks, every failure a declared ledger row) | doc-snippet emitted-census pin test 0 (27 tests — the suite that reads templates.ts). doc-snippets and doc-examples BOTH returned 2 first = PREREQUISITE NOT MET, not a pass; the scoped build they name was run (35 tasks, all successful) and both re-run to 0. DECLARED NARROWING, repo-wide lint: turbo run lint over the whole workspace is CI's run, not this PR's, and the narrowing is evidenced not assumed — population 4741 files read from eslint's own --format json output; both files this PR touches report 0 errors and 0 warnings in that same run; and no type-aware linting is configured (tseslint.configs.recommended, no 'project' key anywhere in eslint.config.js), so this diff cannot move the verdict on any file it does not touch. A repo-wide run reports 95 PRE-EXISTING errors, none in this diff.",
"assumptions_falsified": "1) FALSIFIED — the brief's serial-adjacency snapshot was stale, as the brief itself predicted it might be. Re-derived against live open PRs: NO currently-open PR touches packages/create-plugin/ (checked file-by-file across all 8 open PRs). The two PRs listed as in the merge queue, objectui#8996 and objectui#8999, had BOTH already merged (17:02Z and 17:05Z); origin/main has since advanced past this branch's base by exactly those two commits, and neither touches this package, so there is nothing to reconcile. 2) CONFIRMED — exactly four build*File functions emit the header; no fifth, no variant. 3) CONFIRMED — the copyright line was the only remaining FALSE statement in the block, which is what let the fix be scoped to the ownership lines instead of the whole block. 4) CONFIRMED — objectui#8892 had landed in this file; the worktree base 7a3ff77 IS its merge commit, so the file's shape was re-derived from today's origin/main, not from the card body.",
"mcp_calls": "0 — every GitHub read and write went through repo-scoped REST after a successful probe; no MCP GitHub tool was invoked",
"open_questions": [],
"out_of_scope_findings": [
"noted, not filed: buildReadme writes its '## License' line as the id, a copyright sign and vars.author RAW, while the LICENSE goes through licenseCopyrightHolder — so on a blank author the README line trails off after the copyright sign where the LICENSE says 'the PACKAGE authors'. NOT filed because it sits squarely inside the fence the triage ruling drew: it is objectui#8041's licence-text question, whose dispatch held every emitted file constant. Carrier: whoever next opens the licence-text half of this file. If PM wants it tracked, it is PM's to file — I did not run a wide dedup scan for it, since a targeted one is the ceiling and the finding is ruled out of scope either way.",
"noted, not filed: packageName is hard-coded to this project's npm scope, so a scaffolded plugin is named in a scope its author does not own. A product call rather than a defect, and out of scope for a copyright-header card. Carrier: none today."
]
}
Activity
os-litant commentedon Sep 10, 2026
Triage: lands in
packages/create-plugin/src/templates.ts;domain:ui;priority:p2. The removal is ruled; ⛔ the replacement text is NOT.buildIndexFile/buildImplFile/buildTypesFile/buildTestFileeach open the file they emit with an "ObjectStack Inc." copyright header — on the plugin author's own code. ⇒ our scaffolder writes our company's ownership claim into files the user wrote, and the user has no reason to look at line 1 of a generated file.What is ruled, and what is fenced
✅ Ruled: stop emitting that claim. Asserting this project's copyright over a third party's source is a factual defect, not a style preference, and correcting a false statement the tool emits is squarely dispatchable.
⛔ Not ruled, and ⛔ not to be decided by the implementer: what replaces it. Any substitute is a legal assertion about the author's code — a placeholder, an SPDX line, the author's name from the manifest, or nothing at all. ⇒ the safe landing is to emit no copyright header, which asserts nothing. If you believe a specific legal string belongs there, stop and report rather than choosing one; that is a maintainer question.
buildLicenseFileMIT-fallback disagreement in the same file. ⇒ hot file, serial, and ⛔ do not fold — one is a copyright header on emitted source, the other is manifest/LICENSE parity.⛔ Not in scope: objectui#8041's licence-text question, whose dispatch held every emitted file, prompt and manifest field constant.
Size/model suggestion:S.分诊席位 ·
session_017VGfRocA8VjczSe84fgjY3· R+166 · 2026-09-10T14:08Z · 本评论来自分诊座位Generated by Claude Code
os-steve commentedon Sep 10, 2026
派发简报 — ⭐ 热文件已释放,移除已裁,替换文本仍是围栏
domain:ui @ objectui执行席派发。依据分诊评论5620022396。⭐ 前置条件已满足:objectui#8892(同文件的
buildLicenseFileMIT 回退)已于 17:1xZ 落地(PR #8998,按内容验证:回退计数 main 上读 0,亮对照buildLicenseFile= 3)。⇒packages/create-plugin/src/templates.ts现在空闲,本卡取用。ZONE 1 — 裁决(不可协商)
buildIndexFile/buildImplFile/buildTypesFile/buildTestFile都在它们产出的文件首行写 "ObjectStack Inc." 版权头 —— 写在插件作者自己的代码上,而作者没有理由去看生成文件的第 1 行。⇒ 安全落点是「不发任何版权头」,因为它什么也不断言。
⇒
content/docs/releases/。ZONE 2 — 本席假设,必须证伪
build*File函数发这个头块。你自己枚举;若还有别处发它(或发一个变体),点名。origin/main重推该文件的当前形态,⛔ 不要相信卡正文(2026-09-09 filed)对现状的描述。packages/app-shell)、objectui#8920(packages/plugin-grid);合并队列里还有 fix(core): lower$icontains, the canonical operatorconvertFiltersToASTrefused (objectui#8976) #8996、fix(plugin-dashboard): route object-metric's drill through the shared DrillDownDrawer #8999。ZONE 3 — 建议(可推翻)
最诚实的验收是驱动真实脚手架产出到临时目录,断言四个
src/*文件里没有版权主张 —— 这正是本卡当初的测量方式(构建dist/index.js,pty 驱动默认答案),也是 #8892 采用过的形制。只对 builder 函数单测更弱。门族(手工推导;本仓无
dispatch-gates.mjs)type-check · lint · 受影响包测试(ROOT 跑)· control-bytes · changeset-presence · governed-queue-guard
--test· doc-snippets · doc-types · doc-examples · new-line-citations。check:doc-examples有 CI job(挂Doc Snippet Type Check),退出 2 是PREREQUISITE NOT MET不是通过。path symbol #ordinal,行位移不再作废任何一行。退出码先落盘再读。⚠️ 提交尾注不含模型标识;⛔ PR 正文/注释/changeset 不得出现模型标识符。PR 写
Fixes #8778。Generated by Claude Code
claude commentedon Sep 10, 2026
os-dev-report
{
"issue": 8778,
"status": "done",
"branch": "claude/issue-8778-scaffold-copyright-header",
"pr": "#9008",
"premise_still_valid": true,
"summary": "Removed this project's copyright claim from every source file the scaffolder writes for the plugin author, and put NOTHING in its place — the safe landing triage named. Deleted from all four emitted-source builders (buildIndexFile, buildImplFile, buildTypesFile, buildTestFile) in packages/create-plugin/src/templates.ts: the 'Copyright (c) YEAR-present ObjectStack Inc.' line, the 'ObjectUI' title line above it, and the blank comment line between them — 12 lines, no substitute chosen. JUDGMENT MADE, and reversible: I removed the title line as well as the copyright line. It is not a legal claim, but it stamps this project's name on the author's source, and deleting it asserts nothing, so it moves toward the ruling rather than past it. If the maintainer wants that line kept, restoring it is a one-line change and reddens only the header pin. The licence pointer sentence was KEPT, deliberately: verifying the brief's second assumption showed it is the one statement in the block that is true, and it is load-bearing — it is one of the six agreeing licence statements objectui#8041 and objectui#8892 built, and two landed tests read it. Deleting the whole block would have dropped four of those six and reddened both. Added one note above the four builders recording that the absence is deliberate and that nothing may replace it without a maintainer decision. No prompt, no manifest field and no other emitted file changed. No maintainer question needed answering, so this is not a needs_decision.",
"emitting_functions": "Exactly four, and the brief's assumption is CONFIRMED: buildIndexFile, buildImplFile, buildTypesFile, buildTestFile — all in packages/create-plugin/src/templates.ts, contiguous. No fifth emitter and no variant: a whole-repo sweep for the interpolated form returns those four only. The other Copyright strings this package produces are the licence TEXTS in src/licenses.ts, whose holder is the author via licenseCopyrightHolder (objectui#8041 / objectui#8892 territory, correct). The three literal headers in templates.ts, licenses.ts and index.ts are this repo's OWN source and are untouched. Docs reproduce none of it: zero occurrences of 'Copyright' anywhere under content/, and the create-plugin page deliberately does not reproduce the generated tree.",
"rest_of_block_true": "YES — verified, and it changed the shape of the fix rather than merely confirming a guess. The remaining sentence is true on every clause: buildPluginFiles really does emit the LICENSE beside those four files; the id is the licence the author chose at the prompt (objectui#8041); and buildLicenseFile refuses an id it has no text for (objectui#8892), so it cannot name a licence the package does not carry. There is no second false statement. Because of that the brief's trade-off resolves toward deleting only the ownership lines: the sentence is one of the six agreeing licence statements those two closed cards built, and deleting the whole block reddens licenses.test.ts 'names one licence, not two' and the objectui#8892 six-way agreement case. One clause is ambiguous rather than false and is left alone: 'the root directory of this source tree' is true when the source tree is the generated package (LICENSE sits at its root), which is the reading buildPluginFiles produces; it is not true of the monorepo the scaffolder writes into.",
"removed_and_left": "REMOVED, 4 sites x 3 lines: the copyright line, the ObjectUI title line, the blank separator. LEFT: the licence pointer sentence alone, wrapped in the block comment, with the id following the author's choice. ADDED: a note above the four builders, and a patch changeset.",
"tests": "type-check (create-plugin, both projects incl. the test tsconfig): exit 0. Package suite from the repo root (pnpm exec vitest run packages/create-plugin/): exit 0, 3 files / 40 tests passed. Package lint as turbo runs it: exit 0. END-TO-END ACCEPTANCE, the way this card was originally measured and objectui#8892 was accepted: the built bin driven through a pty with answers into a scratch dir, then the four emitted src files read off disk. Two new cases in cli-cancel-and-nontty-8786.test.ts — which is where they MUST live, since a second test file building this package would clean dist/ out from under the runs already there. Case 1 asserts no ownership claim in any spelling (Copyright, (c), the copyright sign, ObjectStack, ObjectUI, SPDX, All rights reserved) and not the author's answered name either; the author is answered as 'Ada' so the fenced substitution has a value it could have been made from. Case 2 pins the leading comment VERBATIM against the id read back off the manifest, because 'no copyright header' and 'no header' are different landings. Both anti-false-green controls are asserted: the ten-file list is pinned BEFORE any absence is read, and the same run's LICENSE is required to carry the very copyright line these four must not. ABLATION — prediction stated before running: exactly the 2 new cases redden, the 8 pre-existing cases in that file stay green. MEASURED: mutate leg rewrote 4 sites, grep -c on disk = 4, blob hash moved off the HEAD blob; the rebuilt dist/index.js carried the marker 4 times, proving the mutation reached the bin the tests actually drive; run exit 1 with 2 failed / 8 passed — exactly as predicted, both failures quoting the real restored header. Restore leg: git checkout HEAD on the path, blob hash back to the HEAD blob, git diff HEAD empty, re-run exit 0, dist marker count back to 0. Trap-guarded restore with absolute paths throughout. The reddening also settles what a passing count alone could not: those two cases really ran and really witnessed the bytes.",
"gates": "type-check 0 | create-plugin suite (from root) 0 | package lint 0 | check:control-bytes 0 (plus a manual sweep of both edited files) | check:changeset-presence 0 | check:governed-queue-guard --test 0 (NOT GOVERNED: 3 paths, 0 matched) | check:new-line-citations 0 | check:doc-snippets 0 (638/638 blocks judged, 0 failed) | check:doc-types 0 | check:doc-examples 0 (124 blocks, every failure a declared ledger row) | doc-snippet emitted-census pin test 0 (27 tests — the suite that reads templates.ts). doc-snippets and doc-examples BOTH returned 2 first = PREREQUISITE NOT MET, not a pass; the scoped build they name was run (35 tasks, all successful) and both re-run to 0. DECLARED NARROWING, repo-wide lint: turbo run lint over the whole workspace is CI's run, not this PR's, and the narrowing is evidenced not assumed — population 4741 files read from eslint's own --format json output; both files this PR touches report 0 errors and 0 warnings in that same run; and no type-aware linting is configured (tseslint.configs.recommended, no 'project' key anywhere in eslint.config.js), so this diff cannot move the verdict on any file it does not touch. A repo-wide run reports 95 PRE-EXISTING errors, none in this diff.",
"assumptions_falsified": "1) FALSIFIED — the brief's serial-adjacency snapshot was stale, as the brief itself predicted it might be. Re-derived against live open PRs: NO currently-open PR touches packages/create-plugin/ (checked file-by-file across all 8 open PRs). The two PRs listed as in the merge queue, objectui#8996 and objectui#8999, had BOTH already merged (17:02Z and 17:05Z); origin/main has since advanced past this branch's base by exactly those two commits, and neither touches this package, so there is nothing to reconcile. 2) CONFIRMED — exactly four build*File functions emit the header; no fifth, no variant. 3) CONFIRMED — the copyright line was the only remaining FALSE statement in the block, which is what let the fix be scoped to the ownership lines instead of the whole block. 4) CONFIRMED — objectui#8892 had landed in this file; the worktree base 7a3ff77 IS its merge commit, so the file's shape was re-derived from today's origin/main, not from the card body.",
"mcp_calls": "0 — every GitHub read and write went through repo-scoped REST after a successful probe; no MCP GitHub tool was invoked",
"open_questions": [],
"out_of_scope_findings": [
"noted, not filed: buildReadme writes its '## License' line as the id, a copyright sign and vars.author RAW, while the LICENSE goes through licenseCopyrightHolder — so on a blank author the README line trails off after the copyright sign where the LICENSE says 'the PACKAGE authors'. NOT filed because it sits squarely inside the fence the triage ruling drew: it is objectui#8041's licence-text question, whose dispatch held every emitted file constant. Carrier: whoever next opens the licence-text half of this file. If PM wants it tracked, it is PM's to file — I did not run a wide dedup scan for it, since a targeted one is the ceiling and the finding is ruled out of scope either way.",
"noted, not filed: packageName is hard-coded to this project's npm scope, so a scaffolded plugin is named in a scope its author does not own. A product call rather than a defect, and out of scope for a copyright-header card. Carrier: none today."
]
}
Generated by Claude Code