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
2 changes: 1 addition & 1 deletion .agent-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

- 核心规范源:d:\Obsidian\Coding\AGENTS.md
- 检索避坑规范:python d:\Obsidian\Coding\scripts\search-vault.py <报错/模式关键词>
- 发现新踩坑自动沉淀:写草稿至 d:\Obsidian\Coding\08-Inbox\YYYY-MM-DD-{topic}.md
- 发现新踩坑自动沉淀:写草稿至 d:\Obsidian\Coding\99-Inbox\YYYY-MM-DD-{topic}.md
2 changes: 1 addition & 1 deletion .cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

- 核心规范源:d:\Obsidian\Coding\AGENTS.md
- 检索避坑规范:python d:\Obsidian\Coding\scripts\search-vault.py <报错/模式关键词>
- 发现新踩坑自动沉淀:写草稿至 d:\Obsidian\Coding\08-Inbox\YYYY-MM-DD-{topic}.md
- 发现新踩坑自动沉淀:写草稿至 d:\Obsidian\Coding\99-Inbox\YYYY-MM-DD-{topic}.md
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# DeepSeek API Key for Goethe CEFR Grammar Analysis
DEEPSEEK_API_KEY=your_deepseek_api_key_here

# 数据目录:delector.db / progress.db 的落盘位置。留空(不设)= 仓库根,即桌面端默认。
# 数据目录:delector.db / progress.db 的落盘位置。留空(不设)= 平台默认目录
# (Windows: %LOCALAPPDATA%\DeLector;Linux/macOS: ~/.local/share/DeLector),
# **不是**仓库根 —— 只有 DELECTOR_PORTABLE=1(便携模式)才回落到程序所在目录。
#
# 一般**不要**设置本项——docker-compose.yml 已自行设成 /app/data。手工改它之前先读
# README「数据目录与旧版迁移」一节:把数据指到新目录、而旧目录里还留着非空的库文件时,
Expand Down
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ credentials.json
# 学习记录**,单个可达数 MB。上面几条 `*.db*` 都匹配不到 `.bak-<时间戳>` 后缀,
# 故它在仓库根是「未忽略的未跟踪文件」——一次 `git add -A` 就会把用户数据提交进历史。
*.db.bak-*
# 桌面壳运行态产物:launch.log(+ .1 轮转备份)与 lan-address.txt 由 desktop.py 写在
# 数据目录里;而便携模式(DELECTOR_PORTABLE=1)或源码运行时,数据目录就是仓库根
# (data_dir_bootstrap.resolve_data_dir → program_dir())。与上面 *.db* 同一威胁模型:
# 一次 `git add -A` 会把运行态日志(启动堆栈/端口冲突详情)与**内网 IP 地址**提交进历史。
/launch.log
/launch.log.*
/lan-address.txt
*.apkg
*.apk
artifact*.html
Expand All @@ -31,6 +38,9 @@ artifact*.html
# (内部 .gitignore 缺失或工具换版重建目录时,缓存内容会漏进 status)。
.mypy_cache/
.ruff_cache/
# 与上面同理:.superpowers 目前靠自身嵌套 .gitignore(内容 `*`)自忽略;此处补根级兜底,
# 防止工具升级/重建目录但未写回嵌套规则时,整棵工具缓存漏进 status 被 `git add -A` 收走。
.superpowers/
build/
dist/
*.spec
Expand Down
4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Project Guidelines

## 文档路由(先读这个)

- 本仓 agent 文档入口是 `AGENTS.md`(纯路由表):架构 / 运维 / 发版 / 文档落位规则都在那里。进入会话先读它,再按需下沉到具体文档。

## 工程规范与自动化工具路径 (Coding Vault Invariants)

- **核心规范源**:`d:\Obsidian\Coding\AGENTS.md`
Expand Down
12 changes: 12 additions & 0 deletions WORKMEMORY/work.log
Original file line number Diff line number Diff line change
Expand Up @@ -570,3 +570,15 @@ Caps: filesystem-read, filesystem-write, shell-exec
- **纪律**:阈值 pilot(N=5)后固定并写回设计稿;样本集冻结;三臂全量原始输出随报告落盘;**P1 成立亦为正当产出**(届时结论是"当前裁判不足以支撑宣称",表述必须反向收紧)。
- **成本按 token 计、不猜价格**(主实验上限 ≈180 次 chat + 120 次 rater 调用,N=20);harness MUST 有 `--dry-run`(stub chat)以便**无 Key 也能被 CI 测**。
- 后续:本条要动手时走 `/dfs-plan`(harness + 测试 + 种子集三个任务),**不影响**现行 §4.3 口径(无条件「已实现」继续禁用)。

### 2026-10-16 02:30 | codebuddy | NOTE
Caps: filesystem-read, filesystem-write, shell-exec
事件:用户去睡觉,自主推进「评估报告里已定案、不需决策、无危险」的一批修正(分支 `chore/audit-fixes-hygiene`)。
- **P1-2(.gitignore 缺口,swarm/git 管理两席都点到)**:补 `/launch.log`、`/launch.log.*`、`/lan-address.txt` 三条根级规则 + 注释写清威胁模型(便携模式/源码运行时数据目录=仓库根 ⇒ 一次 `git add -A` 会把运行态日志与**内网 IP** 提交进历史)。编排者实测三者由 NOT-IGNORED → IGNORED,且**历史从未进过这三个文件**。
- **P2-4**:补 `.superpowers/` 根级兜底(与 `.mypy_cache/` 同款理由:原靠嵌套 .gitignore 自忽略)。
- **P2-8**:`.env.example` 数据目录注释改正 —— 实测 `resolve_data_dir({})` = `%LOCALAPPDATA%\DeLector`(**不是仓库根**),只有 `DELECTOR_PORTABLE=1` 才回落程序目录。
- **P2-1**:`CLAUDE.md` 加「文档路由(先读这个)」一节指向 `AGENTS.md`(此前只读 CLAUDE.md 的会话完全不知道 architecture/ops 存在)。
- **P2-2**:`.cursorrules` 与 `.agent-rules.md` 的 `08-Inbox` → `99-Inbox`(实测 08-Inbox 不存在、99-Inbox 存在)。
- **守卫测试**:`tests/test_server.py` 新增 `test_runtime_artifacts_protected_by_gitignore`(沿用 keystore 那条惯例 + 多一层 `git check-ignore` 实证 + 与 `desktop.py` 常量对账)。**变异自证**:删掉三条规则 ⇒ 该测试红(判别力成立)。
- **门禁**:守卫 1 passed;`ruff check .` 全绿;`mypy --strict delector` 67 files 0;`--follow-imports=skip tests/test_server.py` 0;契约闸过。全量 `pytest` **1983 passed + 2 skipped + 2 failed** —— 已用 `git stash` 在 master 态复现同样 2 failed,证实是 `tests/conftest.py:16-19` 明文记载的「根目录有库 ⇒ 迁移闸拒绝运行 ⇒ 本地红 / CI 绿」既有分歧,与本 PR 无关(**未删用户库文件**:那属危险操作)。
- **未做(需决策或有危险)**:P1-1 分支纪律机械闸(CI 改动;`gh` 无 workflow scope ⇒ 合并要走 SSH no-ff)、P2-7 `.gitattributes` CRLF 契约(改跨平台 checkout 行为)、P2-6 renormalize、P2-5 `git gc`、P2-3 design-system 状态定夺,以及 swarm audit 的 P0-1/P0-2/P1-1(密钥进备份)等代码级修复。
28 changes: 28 additions & 0 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2527,6 +2527,34 @@ def test_keystore_protected_by_gitignore_and_hook():
assert "base64" in hook and "0x30" in hook, "PKCS12 Base64 检测需经 base64 解码后验文件头"


def test_runtime_artifacts_protected_by_gitignore():
"""桌面壳运行态产物 MUST 被 .gitignore 命中(评审 P1-2:`launch.log`/`lan-address.txt` 曾是缺口)。

威胁模型与 `*.db*` 同族:便携模式(`DELECTOR_PORTABLE=1`)或源码运行时,数据目录
就是仓库根(`data_dir_bootstrap.resolve_data_dir` → `program_dir()`)⇒ 一次
`git add -A` 会把运行态日志(启动堆栈/端口冲突详情)与**内网 IP 地址**提交进历史。
"""
root = ROOT
import subprocess # 本文件惯例:subprocess 只在使用处局部导入

ignore = open(os.path.join(root, ".gitignore"), encoding="utf-8").read()
for pat in ("/launch.log", "/launch.log.*", "/lan-address.txt"):
assert pat in ignore, f".gitignore 缺 {pat}"
# 光有规则字符串不够:必须真的匹配得上(防规则写错、或被后续规则重新包含)
for rel in ("launch.log", "launch.log.1", "lan-address.txt"):
proc = subprocess.run(
["git", "check-ignore", "-q", rel], cwd=str(root), capture_output=True
)
assert proc.returncode == 0, (
f"{rel} 未被 .gitignore 命中(git check-ignore rc={proc.returncode})"
)
# 产物名 MUST 与桌面壳常量一致(防改了常量却忘了改忽略规则)
desktop = open(os.path.join(root, "desktop.py"), encoding="utf-8").read()
assert 'LOG_FILE_NAME = "launch.log"' in desktop
assert 'LOG_BACKUP_SUFFIX = ".1"' in desktop
assert 'LAN_ADDRESS_FILE_NAME = "lan-address.txt"' in desktop


def _pkcs12_b64():
import base64

Expand Down
Loading