Add comprehensive GitHub Actions automation infrastructure - #17
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
… maintenance Co-authored-by: huangyiirene <[email protected]>
Co-authored-by: huangyiirene <[email protected]>
Co-authored-by: huangyiirene <[email protected]>
Co-authored-by: huangyiirene <[email protected]>
Co-authored-by: huangyiirene <[email protected]>
There was a problem hiding this comment.
Pull request overview
This PR adds comprehensive automation workflows to improve CI/CD, security, and maintenance capabilities for the ObjectStack Spec repository. The implementation focuses on establishing robust testing, security scanning, dependency management, and automated documentation deployment.
Changes:
- Added 6 new GitHub Actions workflows for testing, linting, security scanning, documentation deployment, PR automation, and dependency validation
- Enhanced the existing CI workflow with separate test and build jobs, coverage reporting, and artifact management
- Configured Dependabot for automated dependency updates with grouping by type
- Created auto-labeling rules based on file changes and PR size classification
- Added comprehensive documentation for all workflows and automation features
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/ci.yml |
Enhanced with separate test/build jobs, coverage reporting, artifact uploads, and build verification |
.github/workflows/lint.yml |
Adds TypeScript type checking with pnpm caching |
.github/workflows/codeql.yml |
Implements CodeQL security analysis on push, PR, and weekly schedule |
.github/workflows/docs.yml |
Automates documentation building and deployment to GitHub Pages |
.github/workflows/pr-automation.yml |
Implements PR size labeling, auto-labeling, and changeset validation |
.github/workflows/stale.yml |
Manages stale issues and PRs with configurable timeframes |
.github/workflows/validate-deps.yml |
Validates dependencies with security audits and license compliance checks |
.github/dependabot.yml |
Configures automated dependency updates with grouping and scheduling |
.github/labeler.yml |
Defines auto-labeling rules based on changed file paths |
.github/WORKFLOWS.md |
Provides comprehensive documentation of all workflows |
.github/AUTOMATION.md |
Quick reference guide for developers |
|
This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation. |
Co-authored-by: huangyiirene <[email protected]>
Co-authored-by: huangyiirene <[email protected]>
Co-authored-by: Copilot <[email protected]>
|
This PR is very large. Consider breaking it into smaller PRs for easier review. |
…ases — data / type are the only spellings Maintainer ruling on #14791 (2026-09-07, director seat summon #17, decision batch #1, option B): the two overlay props #11284 had deprecated are removed from the ListView block with no deprecation window, now that the consumer fold ships in the pinned console (objectui normalizeListViewSchema at a472b071). - react-blocks.ts: objectName / viewType gone; `data` restated as the required binding (ledgered in REACT_OVERLAY_SHADOWS); REACT_RETIRED_OVERLAY_PROPS is the tombstone ledger; the record:related_list alternative writes the canonical spelling. - lint: boundObjectName reads data.provider === 'object' for ListView (the canonical read step 1 deferred); a retired spelling is a react-prop-retired error carrying the prescription; the step-1 unfolded-deprecation scaffolding is deleted. - showcase pages, the published objectstack-ui skill, the react-pages and validating-metadata guides and one recognizer fixture write the canonical spelling. - ADR-0087: semantic entry ui-react-list-view-binding-aliases-retired under protocol major 18; changeset minor with the BREAKING banner. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x
…26-09-07 is the acceptance act (objectstack-ai#16647) Ruling A on this card's last outstanding record, recorded by the director seat 2026-09-07 (comment 5572010837, decision batch objectstack-ai#1 of summon objectstack-ai#17, maintainer's verbatim reply 「同意」): the Status line becomes Accepted (2026-09-07) — accepted by the maintainer's reply of 2026-09-07 (objectstack#15453, decision batch objectstack-ai#1 of director summon objectstack-ai#17) Dated to the ruling, not to the 2026-08-28 landing: that landing PR (objectstack-ai#12839, commit bbf88be) was merged by the seat account os-sales, and the earlier ruling A of 2026-09-05 (5548576472) explicitly does not cover a seat merge — so "the merge that landed it on main" is NOT the acceptance clause here, and the sibling records' (ADR-0130, ADR-0131) merge clause is deliberately absent. The whole Status field is replaced, not only its state sentence, following the ADR-0130 (objectstack-ai#15704) and ADR-0131 (objectstack-ai#16590) flights: the field carries the state and the act and nothing else. The tail this drops is flagged in the PR body as a judgment call a reviewer can reject. Claude-Session: https://claude.ai/code/session_018dxq7YqsLDMeZDZ5AzsgJX Co-authored-by: Claude <[email protected]>
…ases — data / type are the only spellings (objectstack-ai#14791) (objectstack-ai#16777) * feat(spec)!: retire the ListView objectName / viewType react-tier aliases — data / type are the only spellings Maintainer ruling on objectstack-ai#14791 (2026-09-07, director seat summon objectstack-ai#17, decision batch objectstack-ai#1, option B): the two overlay props objectstack-ai#11284 had deprecated are removed from the ListView block with no deprecation window, now that the consumer fold ships in the pinned console (objectui normalizeListViewSchema at a472b071). - react-blocks.ts: objectName / viewType gone; `data` restated as the required binding (ledgered in REACT_OVERLAY_SHADOWS); REACT_RETIRED_OVERLAY_PROPS is the tombstone ledger; the record:related_list alternative writes the canonical spelling. - lint: boundObjectName reads data.provider === 'object' for ListView (the canonical read step 1 deferred); a retired spelling is a react-prop-retired error carrying the prescription; the step-1 unfolded-deprecation scaffolding is deleted. - showcase pages, the published objectstack-ui skill, the react-pages and validating-metadata guides and one recognizer fixture write the canonical spelling. - ADR-0087: semantic entry ui-react-list-view-binding-aliases-retired under protocol major 18; changeset minor with the BREAKING banner. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x * chore(spec): regenerate the react-blocks contract, api-surface, export-origins and the migration registry; pay the pages.md token ratchet; keep the tracker id out of the lint message Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x * chore(spec): accept the ListView objectName / viewType registry-only inputs in the declaration-parity baseline, with their discharge condition The gate's own --update path (MANIFEST=sdui.manifest.json check:react-declaration-parity --baseline react-declaration-parity.baseline.json --update), then the hand-maintained _acceptedReasons block re-added as the baseline's _note prescribes, with two new entries that state the expiry: accepted only until objectui#8510 removes the two designer inputs from objectui's list-view registration. This moves a ratchet as the mechanical consequence of the objectstack-ai#14791 ruling (option B, no deprecation window); declaring the props back in spec or on the overlay would undo that ruling and is not an exit. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x * test(lint): restore the ObjectForm half of the parse-gate mixed-spelling fixture The `parseable` array in `validate-react-page-props.test.ts` is the FALSE-POSITIVE CONTROL for the syntax gate: every entry asserts only `not.toContain(REACT_PAGE_SOURCE_UNPARSEABLE)`, so it grades the PARSE and nothing else. One entry carries an `ObjectForm` and a `ListView` in a single fragment. Retiring the `ListView` binding aliases re-spelled BOTH halves to `data={{ provider: "object", object: "a" }}`, but only the `ListView` half is in that retirement's scope: `ObjectForm` binds by its own props and carries the shared `OBJECT_NAME` overlay (`packages/spec/src/ui/react-blocks.ts`, the `REACT_BLOCKS` entry for `ObjectForm`), which is `objectName`, required. It has no `data` prop at all — neither in its `interactions` nor in its `dataProps`. The fixture therefore spelled a prop the contract does not carry. Because the array grades parseability only, both spellings parse and CI stayed green: no gate in the repo could see it. Restore the `ObjectForm` half to `objectName="a"` and keep the `ListView` half canonical, which is what the entry was — a genuine MIXED-SPELLING fragment, and a stronger parse fixture than either uniform spelling. Measured over whole file text (never line-oriented, so a hard-wrapped occurrence cannot hide), across the full diff versus the merge base: the `objectName=` prop sites attributed to `ObjectForm` are 16 -> 16 and to `ObjectChart` 36 -> 36 — both unchanged — and `ListView` is the only tag that gains the canonical `data` spelling. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x --------- Co-authored-by: Claude <[email protected]>
… gates read it A narrowing — "these spellings stop being accepted" — could ship to consumers with every gate green. `check-adr-0087-registration.mjs` decided breaking-ness from a hand-written `**BREAKING**` prose banner, so an author who did not type it was classified non-breaking and owed no ADR-0087 disposition. Measured on #16296 (and #14238 one surface earlier), both of which shipped that way. The declaration now carries a closed direction arm — `(widening)` or `(narrowing)` — read once, in `readClause2Line`, and imported by every reader: * `scripts/pm/check-clause2-carriers.mjs` — `CLAUSE2_ARMS`, the arm reader, and the two shapes that must fail closed: a near-arm spelling (`(narrowed)`, the unfilled `(widening|narrowing)` menu) and the self-contradiction `no (widening)`. Both read `malformed`, never as an absent arm. * `scripts/check-adr-0087-registration.mjs` — signal (4). `narrowing` declares breaking; `widening` declares nothing. The `**BREAKING**` banner is KEPT: 52 changesets in stock carry it and nothing else. * `scripts/check-changeset-no-major.mjs` — a declared narrowing owes the same grade a declared widening owes, because inside the launch window a breaking change ships `minor`. The arm is OPTIONAL, and that is a measurement: all five declarations on the open board read `Clause-②: no` with no parenthetical, and all five read byte-identically after this change. AGENTS.md carries the format at net zero lines — its ratchet has no headroom — paid for by deleting the widening-rationale clause and the CI step name the gate prints for itself. Maintainer ruling: director summon #17, decision batch #2 item 1, option B, verbatim 「同意」. Co-Authored-By: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
… gates read it (objectstack-ai#18346) Fixes objectstack-ai#16421 Clause-②: no A gate strengthens; no published runtime contract moves. Stated by the ruling, and re-derived here: the declaration's accept set only grows (the arm is optional and every existing spelling reads byte-identically), and the three gates that read it become stricter, never looser. ## The defect A **narrowing** — "these spellings stop being accepted" — could ship to customers with the release notes saying nothing, and every gate green. `check-adr-0087-registration.mjs` decided breaking-ness from an author's hand-written `**BREAKING**` prose banner; an author who did not type it was classified non-breaking and was asked for no ADR-0087 disposition. Measured, not hypothesised: **objectstack-ai#16296** narrowed `sys_job.timezone` / `sys_report_schedule.timezone` to the IANA value domain and shipped with no banner, no `major` and no `!`. **objectstack-ai#14238** did the same one surface earlier. ## The ruling being executed Director summon objectstack-ai#17, decision batch objectstack-ai#2 item 1, **option B**, maintainer verbatim 「同意」 (comment `5572145955`, 2026-09-07T14:32:32Z). Options A (keep the prose banner) and C (a static accept-set differ) are refused there and are not reopened here. ## What landed | # | deliverable | where | | --- | --- | --- | | 1 | the closed two-arm enumeration in the declaration format | `AGENTS.md` item 3 | | 2 | `readClause2Line` reads the arm — **once**, no second parser | `scripts/pm/check-clause2-carriers.mjs` | | 3 | signal (4): a declared `narrowing` is breaking | `scripts/check-adr-0087-registration.mjs` | | 4 | the level axis reads the arm | `scripts/check-changeset-no-major.mjs` | | 5 | **ONE** ADR-0087 ledger row, recording objectstack-ai#16296 | `packages/spec/src/migrations/entries/semantic/` | >⚠️ **Row 5 is deliberately one row, not the two the ruling names — corrected by the `domain:devx` seat (objectstack-ai#6023) on the dev's measurement.** > The ruling lists objectstack-ai#14238 and objectstack-ai#16296 as the two already-shipped narrowings. **objectstack-ai#14238 is not a narrowing**: its diff is 535 insertions and 0 deletions across 11 files (two nullable columns ADDED, carrying `valueDomain: 'iana_time_zone'` from their first release), and its own shipped changeset says so in writing — *"A NON-BREAKING ADDITION, registered here in writing because ADR-0087's registries have no additive entry kind"*. > A row claiming it narrowed something would be false data in the one ledger this mechanism keeps true, which ADR-0087's objectstack-ai#13080 addendum refuses by name. ⇒ One row is written, the second is **not fabricated**, and the falsified premise is carried to the maintainer rather than silently dropped. >⚠️ **The citation above was wrong in the dispatch order and is corrected here.** The seat's dispatch word cited comment `5573372199`, which answers **HTTP 404**; the real ruling is `5572145955` (HTTP 200, verified by both the dev and the seat). The quoted ruling text itself is unchanged — only the provenance id moved. | 6 | pins for both arms, in both directions | the three gates' self-tests | ### The shape | spelling | reading | | --- | --- | | `Clause-②: yes` | a widening, declared through the value — unchanged | | `Clause-②: yes (widening)` | the same, said out loud | | `Clause-②: yes (narrowing)` | widens one surface, narrows another; both facts are read | | `Clause-②: no (narrowing)` | NOT a widening, but BREAKING — the point of the arm | | `Clause-②: no (widening)` | MALFORMED: the value and the arm contradict each other | (The rows are table cells on purpose: a line-initial second declaration in this body would be a second answer to the same question.) The arm is **optional**, and that is a measurement rather than a kindness: all five declarations on the open board the day this landed carry no parenthetical arm, and all five read byte-identically afterwards (proof below). Two shapes fail **closed** rather than reading as an absent arm, because reading them as absent is the direction a declared narrowing silently disappears in: a near-arm spelling (`(narrowed)`, `(Narrowing)`, `(widen)`) and the unfilled template `(widening|narrowing)`. Both land in `malformed`, the state this reader already owns for "the slot holds something nobody can grade". ## Measurements ### Back-compat — the five in-flight declarations Read from the live GitHub payload, before and after the change, comparing the whole reading object: | PR | reading | arm | | --- | --- | --- | | objectstack-ai#18344 | `declared no` — IDENTICAL | none | | objectstack-ai#18268 | `declared no` (em-dash reasoning, parenthesised identifiers) — IDENTICAL | none | | objectstack-ai#18231 | `near-miss inline-key` — IDENTICAL | n/a | | objectstack-ai#18227 | `declared no` — IDENTICAL | none | | objectstack-ai#18096 | `declared no` — IDENTICAL | none | **5/5 byte-identical** apart from the additive `arm: null` field. Nothing in flight loses its reading. ### `AGENTS.md` — both ratchet axes Its line ratchet has **zero headroom** (1075 lines, ceiling 1075), so the format is carried at **net zero lines**, paid for by deleting content rather than by re-wrapping: - deleted: the widening-rationale clause (`the widening it declares is what makes it more than a patch…`), 93 bytes; - deleted: the CI step name the gate already prints in its own failure, 78 bytes. | axis | before | after | | --- | --- | --- | | lines | 1075 / ceiling 1075 | **1075** — headroom 0, unchanged | | widest line | ≤ 120 bytes | edited lines measure 119 / 118 / 120 / 119 / 81 bytes | | widest table row | 768 / pin 768 | **768**, untouched | `check:pm-skill-ratchet` self-test and run both exit 0. ### Both arms, both directions Every arm pin is a **pair**, because one direction alone cannot tell a reading from a constant — a gate that classified both arms as breaking would satisfy a `narrowing` test while telling a consumer nothing: - `check-adr-0087-registration`: `narrowing` is in `MUST_MATCH_BREAKING`, `widening` is in `MUST_NOT_MATCH_BREAKING`, both on a banner-free `minor` changeset — the exact shape objectstack-ai#16296 shipped in. - `check-changeset-no-major`: same tree, same levels, only the declaration moves — `no (narrowing)` reaches `enforce`, bare `no` reaches `not-declared`. - `check-clause2-carriers`: both arms read; the contradiction, the near-arm family and the unfilled menu are all `malformed`; and three CONTROL rows pin the arm-less spellings unmoved. ## Two judgement calls, declared rather than made quietly 1. **The `**BREAKING**` banner signal is KEPT.** The dispatch word asked for breaking-ness to stop being read from the prose banner. Removing signal (2) would un-declare the **52 changesets in stock** that carry it and nothing else — the gate's own docblock has refused that direction ("narrowing to any one of them would drop real declarations") since it was written, and the ruling's own text asks only that the gate *read the arm*. Signal (4) is added beside it, so breaking-ness no longer **depends** on prose. If the maintainer wants (2) retired, that is a second, deliberate card with its own stock count. 2. **`check-adr-0087-registration` reads the arm from the CHANGESET body, not the PR body.** It has no pull-request payload by construction — `cut-rc.yml` runs it on a `workflow_dispatch` over a whole snapshot range with no PR at all. All three of its existing signals are changeset-local, and the fourth is too. ## Acceptance notes - noted, not filed: `readClause2Correction` does not carry the arm. A correction comment can change a declaration's *value* but not its *direction*. No half-state results today — the arm's three readers are the changeset body (ADR-0087), the PR body (no-major) and this file's own rows, and none of them reads corrections — so this is recorded rather than filed. Carrier: `scripts/pm/check-clause2-carriers.mjs`, the next card that touches `readClause2Correction`. - noted, not filed: the I1/I2 fixture in `check-adr-0087-registration.mjs` staged its import siblings from a hand-written two-name list. Signal (4) added an edge into a nine-module closure including `pm/dispatch-gates.mjs`, so the list is now **derived** by walking real import statements. That is a guard extension inside this card's own defect class, not a drive-by: without it, the next import added over in `pm/` would kill this gate's fixture with an error about neither file. ## 维护者速读(草稿) **改了什么** —「本卡是否放宽契约」这条申报,现在可以再带一个方向:`(widening)` 或 `(narrowing)`,只有这两种拼法。声明 `(narrowing)` 的改动会被三个门禁当作破坏性变更处理:必须写 ADR-0087 处置、必须给到 `minor` 档。`AGENTS.md` 记下格式,行数一行没多。 **为什么改** — 一次「以后不再接受某些写法」的收紧,过去可以在发布说明里一个字都不提就发给客户,所有门禁照样亮绿:门禁是从作者手写的 `**BREAKING**` 横幅判断破坏性的,忘了写就当没有。objectstack-ai#16296 和 objectstack-ai#14238 就是这么发出去的。改完之后,判据是一个封闭的词,不是一段散文。 **风险与代价(含回滚)** — 风险面是「在飞的申报会不会一夜失效」。方向词是可选的,板上 5 个在飞 PR 的申报实测全部逐字不变,已列在上面的表里。代价是作者多写一个词,并且要把同一行抄进 changeset 正文。两条已申报的判断:`**BREAKING**` 横幅这条旧信号保留(库存里 52 个 changeset 只靠它),以及 ADR-0087 门禁从 changeset 正文读方向(它跑 RC 切版时根本没有 PR)。回滚是单笔 revert:三个门禁各自的自测都是新增用例,没有既有用例被改写。 **席位意见** — (留空,复核席定稿) **你要做的** — 确认两件事:① 旧的 `**BREAKING**` 横幅信号保留,是否合你意(裁定原文只说「读分肢」,派发词的转述是「不再从横幅判断」);② 两条 ADR-0087 账本行记的是平台对象列的取值域收紧 —— 该账本服务的是元数据升级者,请确认这两行落在那里是你要的记录位置。 --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) _Generated by [Claude Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_ --- _Generated by [Claude Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_ --- _Generated by [Claude Code](https://claude.ai/code)_ --------- Co-authored-by: claude[bot] <[email protected]>
Implements production-grade CI/CD, security scanning, and maintenance automation for the repository.
Workflows
CI/CD
Security
Automation
Configuration
Documentation
Key Technical Decisions
Post-Merge Setup Required
NPM_TOKENsecret for npm publishingOriginal prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.