diff --git a/.codex/skills/release-workflow/SKILL.md b/.codex/skills/release-workflow/SKILL.md new file mode 100644 index 00000000..512f6169 --- /dev/null +++ b/.codex/skills/release-workflow/SKILL.md @@ -0,0 +1,78 @@ +--- +name: release-workflow +description: Use when the user asks to release, bump version, update changelog/version files, or commit/push a repository release for the Planet repo. Applies the repo's versioning rules, updates all required version-bearing files, updates changelog/version-history, runs minimal relevant validation, and then commits/pushes when requested. +--- + +# Release Workflow + +Use this skill for release-oriented work in this repository. + +## When To Use + +- The user asks to `发版` +- The user asks to bump a version +- The user asks to update `CHANGELOG`, `version-history`, or version files as part of a release +- The user asks to commit/push a release or a publishable bugfix/feature bundle + +Do not use this skill for ordinary commits that are not being released. + +## Versioning Rules + +- `feature` -> bump `+0.1.0` +- `bugfix` -> bump `+0.0.1` +- `docs`, `maintenance`, and `refactor` do not bump by default unless the user explicitly wants a release + +When intent is mixed, prefer the user’s stated release intent. If they ask to release a bugfix bundle, use a patch bump. + +## Required Files + +Every release bump must update these files together: + +- `/home/ray/dev/linkong/planet/VERSION` +- `/home/ray/dev/linkong/planet/frontend/package.json` +- `/home/ray/dev/linkong/planet/pyproject.toml` +- `/home/ray/dev/linkong/planet/uv.lock` +- `/home/ray/dev/linkong/planet/docs/CHANGELOG.md` +- `/home/ray/dev/linkong/planet/docs/version-history.md` + +## Workflow + +1. Inspect the current worktree and current version. +2. Decide the release type from the user request: + - feature + - bugfix + - release without code changes +3. Compute the next version. +4. Update all required version-bearing files. +5. Add a concise but specific changelog entry: + - highlights + - important added/improved/fixed items + - mention the highest-signal files only +6. Update `docs/version-history.md`: + - current dev version + - new timeline row with summary +7. Run the smallest relevant validation available. +8. Before commit, verify the target version is present in all required files. +9. If the user asked for commit/push: + - stage the release files and code changes + - commit with a conventional message + - push to the requested branch, usually `dev` + +## Validation Guidance + +- Prefer scope-matched validation over broad expensive checks +- Typical examples: + - Python backend edits: `python3 -m py_compile ...` + - Frontend edits: use the project-standard frontend build/check if available +- If the environment prevents a check, say that explicitly in the final summary + +## Release Checklist + +Before closing the task, confirm: + +- version bump applied consistently +- changelog updated +- version history updated +- generated/runtime artifacts are not accidentally staged +- validation status recorded +- commit and push completed if requested diff --git a/VERSION b/VERSION index b9c51a1a..c9731ff4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.24.6 +0.24.7 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3db0c156..d899d47d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -7,34 +7,22 @@ This project follows the repository versioning rule: - `feature` -> `+0.1.0` - `bugfix` -> `+0.0.1` -## 0.24.5 +## 0.24.7 Released: 2026-04-10 ### Highlights -- Turned the first BGP AI brief flow into a persistent operator-facing feature with saved Markdown history, tabbed review, and backend-driven fact assembly, while also cutting BGP page load cost by switching the hottest routes away from Python-side full-table scans. +- Formalized repository release hygiene and frontend layout guardrails so repeated versioning chores and recurring layout regressions now have explicit repo-level rules instead of living only in conversation context. ### Added -- Added [backend/app/services/bgp_ai_brief.py](/home/ray/dev/linkong/planet/backend/app/services/bgp_ai_brief.py), building evidence-first BGP brief prompts from incidents, anomalies, observations, and collector coverage instead of relying on manual Playground inputs. -- Added [backend/app/services/bgp_ai_brief_store.py](/home/ray/dev/linkong/planet/backend/app/services/bgp_ai_brief_store.py), persisting generated BGP AI briefs as Markdown files and exposing a stable record shape for history browsing. -- Added [frontend/src/components/MarkdownRenderer/MarkdownRenderer.tsx](/home/ray/dev/linkong/planet/frontend/src/components/MarkdownRenderer/MarkdownRenderer.tsx), giving the frontend a lightweight built-in Markdown renderer for saved AI brief content without introducing a new dependency. -- Added [backend/app/api/v1/bgp.py](/home/ray/dev/linkong/planet/backend/app/api/v1/bgp.py) `GET /bgp/overview/summary`, consolidating the BGP overview summary hot path into a dedicated aggregate endpoint for the BGP workspace. +- Added [release-workflow/SKILL.md](/home/ray/dev/linkong/planet/.codex/skills/release-workflow/SKILL.md), defining the repository release workflow for version bumps, changelog/version-history updates, minimal validation, and commit/push sequencing. ### Improved -- Improved [backend/app/api/v1/ai.py](/home/ray/dev/linkong/planet/backend/app/api/v1/ai.py) and [backend/app/schemas/ai.py](/home/ray/dev/linkong/planet/backend/app/schemas/ai.py) by extending the AI API from one-off analysis calls to saved BGP brief history endpoints, latest-brief lookup, and persisted brief responses. -- Improved [frontend/src/pages/BGP/BGP.tsx](/home/ray/dev/linkong/planet/frontend/src/pages/BGP/BGP.tsx) by moving `AI 简报` into the trailing tab, loading tab data lazily, loading brief history only on demand, and wiring saved brief selection plus regeneration into the operator workflow. -- Improved [frontend/src/services/situational-awareness/http-gateway.ts](/home/ray/dev/linkong/planet/frontend/src/services/situational-awareness/http-gateway.ts), [frontend/src/services/situational-awareness/port.ts](/home/ray/dev/linkong/planet/frontend/src/services/situational-awareness/port.ts), [frontend/src/services/situational-awareness/mock-gateway.ts](/home/ray/dev/linkong/planet/frontend/src/services/situational-awareness/mock-gateway.ts), and [frontend/src/services/situational-awareness/types.ts](/home/ray/dev/linkong/planet/frontend/src/services/situational-awareness/types.ts) by splitting BGP summary, list, and brief-history fetches into more granular gateway methods and de-duplicating in-flight requests on the hot path. -- Improved [frontend/src/index.css](/home/ray/dev/linkong/planet/frontend/src/index.css) by styling the saved BGP brief workspace, Markdown output, history selector, and responsive compact state without re-breaking tab switching. -- Improved [backend/app/services/bgp_collectors.py](/home/ray/dev/linkong/planet/backend/app/services/bgp_collectors.py) by replacing full-table ORM loading with database-side collector aggregation, latest-record lookup, and top-event summarization for the collector coverage hot path. - -### Fixed - -- Fixed the BGP tab rendering regression in [frontend/src/index.css](/home/ray/dev/linkong/planet/frontend/src/index.css) where forcing tab panes to `display: flex` accidentally kept hidden panes visible and made the first tab look permanently locked. -- Fixed [backend/app/api/v1/bgp.py](/home/ray/dev/linkong/planet/backend/app/api/v1/bgp.py) so `events`, `anomalies`, and `incidents` no longer fetch whole tables into Python just to apply filtering, pagination, and counting. -- Fixed the repository workflow around saved BGP brief artifacts by ignoring [data/ai/bgp-briefs/](/home/ray/dev/linkong/planet/data/ai/bgp-briefs/) in [.gitignore](/home/ray/dev/linkong/planet/.gitignore) instead of leaving runtime Markdown output to pollute git status during normal operator use. +- Improved [rules.md](/home/ray/dev/linkong/planet/rules.md) by adding mandatory release-workflow requirements and a new frontend layout constraint section covering single-screen workspaces, overflow ownership, tab-pane behavior, compact-mode expectations, and readable-card fallbacks. +- Improved [frontend-layout-guidelines.md](/home/ray/dev/linkong/planet/docs/frontend-layout-guidelines.md) by summarizing the recurring Earth, Playground, BGP, and admin-layout regressions into concrete constraints for future frontend work, including “prefer scrollbars over unreadable compression” and “do not treat every tab as a table pane.” ## 0.24.6 diff --git a/docs/frontend-layout-guidelines.md b/docs/frontend-layout-guidelines.md index bf35c337..81b5c96d 100644 --- a/docs/frontend-layout-guidelines.md +++ b/docs/frontend-layout-guidelines.md @@ -82,6 +82,145 @@ - 工作区容器通常需要 `display: flex` - 真正的滚动节点要显式 `overflow: auto` +### 6. 卡片不能被压到不可读 + +历史上我们反复踩到的问题不是“没有滚动条”,而是: + +- 卡片被 `flex` 压缩得只剩一小条可视区域 +- 文字能渲染,但读不完整 +- 内容其实存在,却被 `overflow: hidden` 裁掉 + +因此后续约束是: + +- 先保证卡片有可读的最小高度 +- 如果继续压缩会影响阅读,就切换成内部滚动 +- 不要为了“保持一屏”而把正文、表格、描述区压成无法阅读的条状区域 + +### 7. Tabs 不是天然安全的布局容器 + +历史上 Tabs 相关回归非常多,典型问题包括: + +- 隐藏 tab pane 因为自定义 `display: flex` 而重新露出来 +- 所有 tab 被强行套用同一套高度/overflow 规则 +- 表格 tab 能工作,但 markdown / help / diagnostics tab 被压坏 + +因此约束是: + +- `Tabs` 里的每类内容都要单独定义自己的布局策略 +- 表格 tab 可以是“固定高度 + 内部滚动” +- 文档/Markdown tab 更适合“tab pane 自身滚动 + 内容正常文档流” +- 如果覆盖组件库样式,必须同时检查 hidden 状态是否仍然成立 + +### 8. 摘要区优先进入紧凑模式,而不是挤压正文 + +历史经验表明,最容易被误处理的是顶部摘要卡: + +- 它们经常为了“都放下”被强行压窄 +- 然后正文、表格、AI 结果区一起失去主空间 + +后续统一约束: + +- 小屏或高缩放时,摘要卡优先: + - 降低 padding + - 改成横向滚动 + - 改成更紧凑的网格 +- 不要优先牺牲主工作区的可视面积 + +### 9. 长文档类内容优先保证阅读体验 + +像下面这些内容,不能直接套用“表格工作区”的逻辑: + +- AI 简报 +- 运行日志 +- 原始 JSON +- 帮助说明 +- 多段描述性文本 + +这些区域应该优先满足: + +- 标题和元信息稳定可见 +- 正文有明确的最小可读高度 +- 正文滚动策略单独定义 +- 支持 Markdown 表格、分隔线、引用、代码块等结构 + +### 10. 高度关键路径要少包一层 + +历史上不少滚动问题不是组件本身错,而是多包了一层之后: + +- 高度链路断掉 +- `min-height: 0` 没传下去 +- `overflow` 责任被吃掉 + +因此: + +- 对高度关键区域,优先使用最直接的 DOM 结构 +- 使用 `Space`、额外包装 `div`、第三方布局容器时,要确认它们不会改变滚动和高度语义 +- 如果一个区域已经出现“内容明明有,但只剩一条缝”,优先怀疑中间包装层 + +## 历史坑位总结 + +从 Earth、Playground、BGP、DataSources 这些页面的 bugfix 可以归纳出几类高频坑: + +### 1. 用 `overflow: hidden` 掩盖布局问题 + +表面上看页面“整齐了”,实际上会导致: + +- 内容被裁掉 +- tab 内容只剩一条缝 +- 面板明明渲染成功,但用户看不见 + +正确做法: + +- 让真正的内容节点滚动 +- 不要让上层容器无差别裁剪所有子内容 + +### 2. 把所有 tab 当成同一种内容 + +表格、Markdown、帮助卡、日志流的空间需求完全不同。 + +正确做法: + +- 表格:固定工作区 + 内部滚动 +- 文档:普通流式内容 + pane 级滚动 +- 侧边说明:内容驱动高度,不强行拉满 + +### 3. 只做视觉缩小,不做空间重分配 + +这会导致: + +- 卡片文字被截断 +- 表格只剩 1 到 2 行 +- 按钮和筛选区挤成一团 + +正确做法: + +- 紧凑模式优先重排 +- 横向滚动摘要区 +- 折叠/收纳次级模块 + +### 4. 父容器高度链不完整 + +这是最常见的内部滚动失效原因。 + +检查顺序: + +1. 外层是否真的有确定高度 +2. flex 父容器是否带了 `min-height: 0` +3. 真正滚动节点是否明确 `overflow: auto` +4. 中间包装层是否偷偷改了布局语义 + +### 5. UI 状态和显示状态不同步 + +Earth 相关改动里反复出现: + +- 图层隐藏了,但 hover/lock 还在 +- tooltip 还在显示旧对象 +- legend 没跟着切换 + +这类约束同样适用于后台页面: + +- 被隐藏、卸载、切换出视图的内容,不应继续保留活跃交互状态 + ## 推荐实现模式 ### 页面骨架 @@ -149,9 +288,11 @@ - 页头、摘要区、主工作区能否同时出现 - 主工作区是否拿到了页面中最多的高度 - 表格或明细溢出时,滚动条是否出现在模块内部 +- 卡片是否被压缩到文字显示不完整;如果会,是否已经切换为内部滚动 - 浏览器缩放到 `125%` / `150%` 时是否仍可用 - 低高度窗口下是否还保有合理的可见内容行数 - Tabs、Card、Table 在 overflow 时是否仍可操作 +- 非表格 tab(Markdown、帮助说明、日志)是否有独立且合理的滚动策略 ## 落地顺序 diff --git a/docs/version-history.md b/docs/version-history.md index 1704fa3d..bab08169 100644 --- a/docs/version-history.md +++ b/docs/version-history.md @@ -16,7 +16,7 @@ ## Current Version - `main` 当前主线历史推导到:`0.16.5` -- `dev` 当前开发分支历史推导到:`0.24.6` +- `dev` 当前开发分支历史推导到:`0.24.7` ## Timeline @@ -79,6 +79,7 @@ | `0.24.4` | bugfix | `dev` | `pending` | polish `planet.sh` AI Provider rebuild stage boundaries, hide raw Compose build logs on success, and add explicit image-build completion feedback | | `0.24.5` | bugfix | `dev` | `pending` | add persistent BGP AI briefs with Markdown history, lazy-load BGP tabs, and move BGP hot-path filtering and aggregation back into the database | | `0.24.6` | bugfix | `dev` | `pending` | batch datasource and visualization hot-path queries, fix BGP collector JSON extraction, and rebuild the BGP AI brief tab layout and markdown rendering | +| `0.24.7` | bugfix | `dev` | `pending` | formalize release workflow and frontend layout constraints with repo rules and a reusable release skill | ## Maintenance Commits Not Counted as Version Bumps diff --git a/frontend/package.json b/frontend/package.json index c6b2db44..0be6b0df 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "planet-frontend", - "version": "0.24.6", + "version": "0.24.7", "private": true, "packageManager": "bun@1", "dependencies": { diff --git a/pyproject.toml b/pyproject.toml index 1981ac88..ede4323f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "planet" -version = "0.24.6" +version = "0.24.7" description = "智能星球计划 - 态势感知系统" requires-python = ">=3.14" dependencies = [ diff --git a/rules.md b/rules.md index cce03fa5..68c78346 100644 --- a/rules.md +++ b/rules.md @@ -239,3 +239,57 @@ class BaseCollector: - Python-side post-filtering - repeated summary queries that can be merged - repeated per-request recomputation that should be cached or aggregated once + +--- + +## Release Workflow - MANDATORY + +- When the user asks to `发版`, `bump version`, `release`, or `推送发布类改动`, treat it as a release workflow, not a plain commit +- Apply repository versioning rules consistently: + - `feature` -> `+0.1.0` + - `bugfix` -> `+0.0.1` + - `docs / maintenance / refactor` do **NOT** bump version unless the user explicitly wants a release anyway +- A release bump **MUST** update all version-bearing files together: + - `VERSION` + - `frontend/package.json` + - `pyproject.toml` + - `uv.lock` +- A release bump **MUST** update release records together: + - `docs/CHANGELOG.md` + - `docs/version-history.md` +- Before committing a release, verify the target version appears consistently in all required files +- Before pushing a release, run the smallest relevant validation available for the changed scope and report what was or was not validated +- If runtime output directories are part of the feature flow, confirm they are ignored appropriately so release commits do not accidentally include generated artifacts +- If asked to commit/push release work, do **NOT** skip changelog or version-history updates just because the code changes are small +- Use the repo skill at `/home/ray/dev/linkong/planet/.codex/skills/release-workflow/SKILL.md` whenever performing a release workflow for this repository + +--- + +## Frontend Layout - MANDATORY + +- Backend/admin pages must be designed as a `single-screen workspace` first, not as a long vertically stacked document +- In common desktop viewports, users should be able to see: + - page header + - summary/controls + - the main work area +- The main work area must get the majority of the available height; secondary cards must not crowd it out +- If a card or panel would be compressed until text, controls, or tables become unreadable, stop shrinking it and give that region an internal scrollbar instead +- On small screens, high browser zoom, or reduced viewport height, switch to a compact mode or horizontal summary scrolling before allowing important content to be crushed +- Overflow ownership must be explicit: + - parent height chain must be valid + - height-constrained flex parents need `min-height: 0` + - only the intended scroll node should own `overflow: auto` +- Do **NOT** rely on `overflow: hidden` as the final fix for a crowded layout unless another child container is explicitly responsible for scrolling +- For tabs: + - hidden tab panes must stay hidden + - do not override library hidden-pane selectors in a way that makes inactive content visible + - each tab must define its own scroll strategy instead of inheriting a one-size-fits-all table layout +- For long-form content such as AI briefs, logs, markdown, raw JSON, or help text: + - prefer normal document flow inside the content block + - if height is constrained, use a stable minimum readable height plus scrolling + - do not let flex compression collapse the readable area into a thin strip +- Avoid brittle viewport sizing: + - prefer `height: 100%` chains over naive `100vh/100vw` usage in embedded/admin shells + - verify layouts under browser zoom `125%` and `150%` +- Avoid using wrapper components with implicit layout behavior, such as `Space`, for height-critical scroll regions unless their generated DOM is fully accounted for +- Any UI state that hides data or a layer must also reconcile related hover/lock/tooltip/selection state so hidden content is not still “active” in the UI diff --git a/uv.lock b/uv.lock index b5626750..862e6a28 100644 --- a/uv.lock +++ b/uv.lock @@ -475,7 +475,7 @@ wheels = [ [[package]] name = "planet" -version = "0.24.6" +version = "0.24.7" source = { virtual = "." } dependencies = [ { name = "aiofiles" },