Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions .github/workflows/adversarial.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ jobs:
- name: Checkout exact revision
uses: actions/checkout@v7
with:
ref: ${{ github.sha }}
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Install JavaScript test runtime
uses: actions/setup-node@v6
with:
Expand All @@ -38,9 +39,16 @@ jobs:
if: always()
uses: actions/upload-artifact@v7
with:
name: wcode-native-layout-${{ github.sha }}
path: target/wcode-*-audit.json
if-no-files-found: warn
name: wcode-native-layout-${{ github.run_id }}-${{ github.run_attempt }}
path: |
target/wcode-webkit-layout.json
target/wcode-browser-audit.json
target/wcode-layout-fixture.html
target/wcode-browser-fixture.html
src/ui/intelligence_web/styles/
tests/unit/ui/browser_webkit.swift
tests/unit/ui/layout_webkit.swift
if-no-files-found: error
retention-days: 14

adversarial:
Expand All @@ -52,7 +60,8 @@ jobs:
- name: Checkout exact revision
uses: actions/checkout@v7
with:
ref: ${{ github.sha }}
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
Expand All @@ -65,14 +74,18 @@ jobs:
- name: Compile adversarial Rust cases
run: cargo test --locked --lib --no-run
- name: Run all 30 rounds against stable inputs
run: node tests/release_audit.cjs
run: |
git rev-parse HEAD > target/wcode-audit-revision.txt
node tests/release_audit.cjs
- name: Retain revision-bound audit results
if: always()
uses: actions/upload-artifact@v7
with:
name: wcode-adversarial-30-${{ github.sha }}
name: wcode-adversarial-30-${{ github.run_id }}-${{ github.run_attempt }}
path: |
target/wcode-audit-revision.txt
target/wcode-adversarial-30.json
target/wcode-*-audit.json
if-no-files-found: warn
target/wcode-webkit-layout.json
target/wcode-browser-audit.json
if-no-files-found: error
retention-days: 14
4 changes: 4 additions & 0 deletions docs/manual/releases/v0.7.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ Unregistered hosts, invalid origins and unauthenticated requests still fail clos

Code statistics use shrinkable label/value tracks and a separate progress row instead of fixed widths that overlap adjacent columns. Verification previews use content-driven height, wrapping long test names and a dedicated fail-fast row layout. The evidence inspector stacks at constrained widths. English descriptive copy no longer exposes internal translation keys.

Long evidence identifiers, policy/model chips and diagnostic lines wrap inside the inspector rather than forcing a horizontal scrollbar or extending beyond their grid row. Regression checks cover the inspector's inner sections as well as the outer card; the fix preserves complete text rather than hiding overflow.

Refresh errors distinguish authorization, Host/origin denial, timeout, malformed responses and rendering exceptions without placing internal paths or stacks in page text. Full project snapshots have a bounded 120-second deadline; lightweight cached requests retain 30 seconds. Rendering failure cannot certify the new snapshot revision. Adaptive checks remain a read-only planning preview, not execution from the Observatory.

## Repository integrity and fail-closed release gates
Expand All @@ -53,4 +55,6 @@ Run `cargo test --locked`, `cargo clippy --locked --all-targets -- -D warnings`,

`node tests/release_audit.cjs` runs 30 distinct adversarial rounds on macOS, with independent Rust and Web lanes, nonempty-test checks, bounded execution and a before/after input digest. Results are recorded in `target/wcode-adversarial-30.json`. The full production-page WebKit audit covers 96 combinations of 12 widths (320–1920 pixels), English/Chinese, light/dark and proof/overview. Portable rendering-failure scenarios are included in `cargo test`; the actual WebKit audit also runs in macOS CI.

The full-page runner hosts WebKit in a real window, waits for fonts and animation frames, and validates the requested viewport. Navigation failures and timeouts produce partial failure reports instead of a silent hang. The independent adversarial workflow preserves the synthetic HTML, shipped CSS, layout reports, exact checked-out revision and 30-round results for diagnosis; failed geometry checks are not skipped to publish.

Publication follows reviewed commit → non-force push → successful CI for that exact SHA → version tag → distribution builds and smoke tests. After installation, restart the running wcode process, reconnect MCP and reopen the Observatory; rebuilding a binary does not update an already-running server.
4 changes: 4 additions & 0 deletions docs/manual/releases/v0.7.5.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ v0.7.5 加固入口所有权、TUI 按键分发、观测台渲染与仓库验证

代码统计改用可收缩的名称/数值列,进度条单独占一行,不再因固定列宽覆盖相邻统计。验证预览按内容计算高度,长测试名自动换行,快速失败列表使用独立布局。受限宽度下证据检查器移到下方。英文说明不再暴露内部翻译键名。

过长的证据标识、策略/模型标签和诊断文本会在检查器内部换行,不再撑出横向滚动条或超出网格行。回归检查同时覆盖外层卡片和内部各节,修复保留完整文本,不以隐藏溢出内容掩盖问题。

刷新错误区分授权、Host/Origin 拒绝、超时、响应异常和渲染异常,不在页面直接显示内部路径或堆栈。完整项目快照请求使用 120 秒有界等待,轻量缓存请求保持 30 秒。渲染失败不能把新快照版本记为成功;自适应检查仍是只读规划预览,不会从观测台直接执行。

## 仓库完整性与失败关闭的发布门禁
Expand All @@ -53,4 +55,6 @@ wcode help-all --json

macOS 上运行 `node tests/release_audit.cjs` 可执行 30 轮不同场景的对抗检查:Rust 与 Web 两条独立验证线并行,每项要求实际命中测试、执行有界,并比对检查前后的输入摘要。结果保存在 `target/wcode-adversarial-30.json`。完整生产页面的 WebKit 审计覆盖十二种宽度(320–1920 像素)、中英文、明暗主题与证据/总览页面的 96 种组合。跨平台渲染故障场景已接入 `cargo test`,macOS CI 也执行真实 WebKit 审计。

完整页面测试将 WebKit 挂载到真实窗口,等待字体和动画帧就绪,并核对实际视口宽度。导航失败或超时会输出部分失败报告,不再静默卡住。独立对抗检查工作流保留合成测试页、随包 CSS、布局报告、实际检出的提交号和 30 轮结果,便于诊断;不会跳过布局失败来发布。

发布顺序为审查提交 → 非强制推送 → 精确 SHA 的 CI 全绿 → 版本标签 → 分发包构建与冒烟测试。安装后必须重启正在运行的 wcode、重新连接 MCP 并重新打开观测台;构建新二进制不会自动更新旧服务进程。
5 changes: 5 additions & 0 deletions src/ui/intelligence_web/styles/data.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions tests/unit/ui/browser_webkit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class BrowserAudit: NSObject, WKNavigationDelegate {
const describe=el=>{
if(!el)return null;
const b=r(el),s=getComputedStyle(el);
return {tag:el.tagName,id:el.id,className:el.className,left:b.left,right:b.right,top:b.top,bottom:b.bottom,width:b.width,height:b.height,scrollWidth:el.scrollWidth,clientWidth:el.clientWidth,display:s.display,position:s.position,minWidth:s.minWidth,maxWidth:s.maxWidth,gridTemplateColumns:s.gridTemplateColumns,gridTemplateRows:s.gridTemplateRows,margin:s.margin,padding:s.padding,overflow:s.overflow,transform:s.transform};
return {tag:el.tagName,id:el.id,className:el.className,left:b.left,right:b.right,top:b.top,bottom:b.bottom,width:b.width,height:b.height,scrollWidth:el.scrollWidth,clientWidth:el.clientWidth,scrollHeight:el.scrollHeight,clientHeight:el.clientHeight,display:s.display,position:s.position,minWidth:s.minWidth,maxWidth:s.maxWidth,gridTemplateColumns:s.gridTemplateColumns,gridTemplateRows:s.gridTemplateRows,margin:s.margin,padding:s.padding,overflow:s.overflow,transform:s.transform};
};
const check=(ok,label,el=null,parent=null)=>{
if(ok)return;
Expand All @@ -27,7 +27,7 @@ final class BrowserAudit: NSObject, WKNavigationDelegate {
check(window.__layoutReady===true,'production boot failed');
check(document.documentElement.scrollWidth<=innerWidth+1,'page overflow',document.documentElement);
check(document.querySelectorAll('[role="tab"][aria-selected="true"]').length===1,'tab selection');
for(const selector of ['.bar-row','.frontier-row','.evidence-ledger-head','.evidence-ledger-row','.evidence-inspector-identity','.proof-signal-card','.workspace-context','.global-bar']){
for(const selector of ['.bar-row','.frontier-row','.evidence-ledger-head','.evidence-ledger-row','.evidence-inspector-identity','.proof-signal-card','.workspace-context','.global-bar','.evidence-inspector-card','.evidence-inspector-section','.evidence-inspector-card .inspector-chip-list','.evidence-inspector-section pre']){
document.querySelectorAll(selector).forEach((el,i)=>{
if(!visible(el))return;
check(el.scrollWidth<=el.clientWidth+1,selector+' content overflow '+i,el,el.parentElement);
Expand All @@ -48,7 +48,11 @@ final class BrowserAudit: NSObject, WKNavigationDelegate {
}
const header=document.querySelector('.global-bar');
const headerChildren=header&&header.scrollWidth>header.clientWidth+1?[...header.querySelectorAll('*')].filter(el=>visible(el)&&(r(el).right>r(header).right+1||r(el).left<r(header).left-1)).slice(0,12).map(describe):[];
return {width:innerWidth,language:state.language,theme:state.theme,tab:state.workspaceTab,errors,diagnostics,headerChildren};
return {width:innerWidth,language:state.language,theme:state.theme,tab:state.workspaceTab,errors,diagnostics,headerChildren,
scrollX,scrollY,devicePixelRatio,fontStatus:document.fonts.status,
coarsePointer:matchMedia('(pointer:coarse)').matches,
gutter:getComputedStyle(document.documentElement).getPropertyValue('--page-gutter-x'),
media:[1680,1460,1240,900,720,520].map(width=>({width,matches:matchMedia(`(max-width:${width}px)`).matches}))};
})()
"""#
override init(){
Expand All @@ -74,7 +78,8 @@ final class BrowserAudit: NSObject, WKNavigationDelegate {
func finish(_ reason:String? = nil){
guard !finished else{return};finished=true
let failures=reports.reduce(0){$0+(($1["errors"] as? [String])?.count ?? 1)} + (reason == nil && reports.count == scenarios.count ? 0:1)
let report:[String:Any]=["suite":"full-browser-adversarial","failures":failures,"cases":reports.count,"expected_cases":scenarios.count,"results":reports,"runner_error":reason ?? ""]
let failedCases=reports.filter{!(($0["errors"] as? [String])?.isEmpty ?? false)}.count
let report:[String:Any]=["suite":"full-browser-adversarial","failures":failures,"failed_cases":failedCases,"cases":reports.count,"expected_cases":scenarios.count,"results":reports,"runner_error":reason ?? ""]
do {
let data=try JSONSerialization.data(withJSONObject:report,options:[.prettyPrinted,.sortedKeys])
try data.write(to:URL(fileURLWithPath:"target/wcode-browser-audit.json"),options:.atomic)
Expand Down