diff --git a/docs/decision_log.md b/docs/decision_log.md index 4738458..2fbd36b 100644 --- a/docs/decision_log.md +++ b/docs/decision_log.md @@ -49,3 +49,27 @@ console script `pop-fem-audit-tools run-llm ...` (`[project.scripts]`)。理由:後續多支工具共用單一入口, `--help` 可列出全部子命令,重現文件穩定。 +- **資料儲存架構定案**:commit 判準——凡能由「committed 輸入+ + committed 程式」決定性再生者不 commit;源頭、外部捕捉、人工 + 著作以文字格式 commit。工作儲存採 SQLite 單檔 + (`tools/instance/`,generated、不進 git;歌詞全文入 DB 故無 + 版權疑慮),schema 以 SQLAlchemy 2.0 typed ORM 定義,設定經 + pydantic-settings(`.env`)。`results/` 報表 CSV 為「可再生仍 + commit」的唯一例外,理由:論文引用穩定性、審稿人零門檻、 + 撰稿期數字變動可 diff。(本條經多輪辯證後定案,推翻 Claude + 最初的全 CSV 方案。) +- **資料模型**:songs、chart_entries(1—N)、artists、 + song_artists(M—N:角色、署名順序)、lyrics(1—1);領域 + 不變量檢查內建 `build-db`,違規即失敗。 +- **歌手背景擴充與防火牆**:歌手資料擴為實體表(QID、性別、 + 型態、曲風、國籍),women-power 候選的歌手另做深度背景 + (族裔以公開自我認同為準、音樂場景),供人工解讀與論文 + 討論;**歌手背景絕不進 LLM 輸入**(歌詞-only),避免光環 + 偏誤污染條件 A/B 實驗。 +- **沿用先導研究歌詞捕捉**(lyrics.json,684 首,2018–2025): + 只匯入識別欄位與歌詞本文,pilot 分析欄位不匯入;以 + (year, rank) 精確匹配。出處記於 `lyrics_provenance.csv`: + source(原始 API)與 method(pilot-import / api-fetch) + 兩層;取得日期不可考者不假造,僅記可證上界。 +- **`run_llm` 改走 pydantic-settings 統一設定**(刪手寫 .env + parser),與 `config.py` / `database.py` 一致。 diff --git a/docs/project_structure.md b/docs/project_structure.md index 86324d0..2849ac1 100644 --- a/docs/project_structure.md +++ b/docs/project_structure.md @@ -1,7 +1,7 @@ # 專案目錄結構 -(2026-07-30 討論定案版;分析管線已改為 API script 路線, -定義檔不再放 `.claude/agents/`) +(2026-07-30 討論定案;2026-07-31 更新為 tools/ 子專案與 +SQLite 工作儲存架構) ``` pop-fem-audit/ @@ -10,22 +10,29 @@ pop-fem-audit/ │ # 絕不放理論、codebook、預期結果) ├── .gitignore # data/lyrics/、.env、scratch ├── conference_abstract.md # pilot 摘要(投稿版) -├── data/ +├── data/ # 源頭與捕捉層(文字格式,進 git) │ ├── yearend_hot100_2016_2025.csv # 原始榜單(唯一手放原始檔) -│ ├── songs_unique.csv # 衍生:去重歌曲表(song id) -│ ├── artists_gender.csv # 衍生:演唱者性別後設資料 -│ └── lyrics/ # 歌詞快取(gitignored,版權) +│ ├── artists_wikidata.csv # 捕捉:Wikidata 快照 +│ ├── artists_overrides.csv # 人工核定 / 深度背景 +│ ├── lyrics_provenance.csv # 歌詞出處(source + method) +│ └── lyrics/ # 歌詞 .txt 快取 +│ # (gitignored,版權) ├── prompts/ # LLM 定義檔(逐字作為 system prompt) │ └── _v.md # 版本化:screen_v1.md、judge_v2.md… ├── tools/ # 輔助工具子專案(src-layout) -│ ├── pyproject.toml # 套件 pop_fem_audit_tools; +│ ├── pyproject.toml # 發行名 pop-fem-audit-tools; │ │ # pip install -e tools/ 安裝 -│ ├── src/pop_fem_audit_tools/ # deterministic Python 程式 -│ │ │ # (runner、抓歌詞、統計、圖表) +│ ├── README.rst LICENSE MANIFEST.in .env.example .gitignore +│ ├── docs/ # Sphinx API 文件 +│ ├── instance/ # SQLite 工作儲存(generated、 +│ │ # gitignored;含歌詞全文) +│ ├── src/pop_fem_audit_tools/ │ │ ├── __main__.py # 套件 CLI 進入點(分派子命令) +│ │ ├── config.py # pydantic-settings 設定(.env) +│ │ ├── database.py # SQLAlchemy engine / session / Base │ │ └── run_llm.py # API runner:2+1 協定、Batch API、 │ │ # 自動寫入 runs/;執行方式 -│ │ # python -m pop_fem_audit_tools run-llm +│ │ # pop-fem-audit-tools run-llm │ └── tests/ # 單元測試(unittest) ├── runs/ # 每次執行的完整稽核紀錄(進 git) │ └── <階段>/<日期>-<定義檔版本>/ @@ -35,7 +42,8 @@ pop-fem-audit/ │ ├── arbitration.jsonl # 仲裁輸出 │ └── meta.json # model ID、temperature、時間戳、 │ # batch ID、一致率 -├── results/ # 仲裁後最終衍生表(論文引用來源) +├── results/ # 論文引用的報表 CSV(export 產出; +│ # 「可再生仍 commit」的唯一例外) ├── docs/ │ ├── research_plan.md # 研究步驟規劃(本檔之姊妹篇) │ ├── project_structure.md # 本檔 @@ -55,8 +63,14 @@ pop-fem-audit/ 論文只引 `results/`,其來源可回溯至 `runs/`。 - **`prompts/` 用檔名版本化**(不只靠 git 歷史):定義檔版本是 論文附錄的引用單位,須可直接指名(如 judge_v2.md)。 -- **API 金鑰**放 `.env`(gitignored),script 由環境變數讀取, - 絕不寫入 repo。 +- **Commit 判準**:能由「committed 輸入+程式」決定性再生者不 + commit(SQLite 工作儲存、LLM 輸入檔);源頭、捕捉、人工著作 + 一律以文字 commit。`results/` 報表是唯一例外(引用穩定性、 + 審稿人零門檻、撰稿期可 diff)。詳見 `research_plan.md` + 「資料儲存與模型」。 +- **設定**經 pydantic-settings 統一:`.env`(gitignored,範本 + `tools/.env.example`)供應 `SQLALCHEMY_DATABASE_URL` 與 + `ANTHROPIC_API_KEY`,絕不寫入 repo。 - **CLAUDE.md 極簡**:實測證實 Claude Code subagent 會繼承專案 CLAUDE.md 全文,故其中只放工作流程規則,領域知識一律放 `docs/`(subagent 不會自動讀到)。 diff --git a/docs/research_plan.md b/docs/research_plan.md index 404f57e..0476b4c 100644 --- a/docs/research_plan.md +++ b/docs/research_plan.md @@ -1,6 +1,7 @@ # 研究步驟規劃 -(2026-07-30 討論定案版;後續變更請記入 `decision_log.md`) +(2026-07-30 討論定案、2026-07-31 增補資料架構; +後續變更請記入 `decision_log.md`) ## 總體框架 @@ -24,12 +25,54 @@ 人工黃金標準終審。可重現性定義為「程序透明+可稽核」: 公開定義檔、記錄 model ID 與執行時間、保存全部原始輸出。 +## 資料儲存與模型(2026-07-31 定案) + +- **Commit 判準**:凡能由「committed 的輸入+committed 的程式」 + 決定性再生者,不 commit;凡不能者——源頭資料、外部世界的 + 捕捉(Wikidata 快照、LLM 原始輸出)、人工著作(核定、編碼) + ——一律以文字格式 commit。格式跟著層次走,不跟著偏好走。 +- **分層**: + - 源頭:原始榜單 CSV(進 git)。 + - 捕捉:Wikidata 快照 CSV、人工 overrides CSV、你的編碼 + CSV、`runs/` JSONL(皆進 git);歌詞 `.txt` 快取 + (版權因素 gitignored,為已知的稽核缺口)。 + - 工作儲存:SQLite 單檔(`tools/instance/`,generated、 + 不進 git),SQLAlchemy 2.0 typed ORM 定義 schema, + 設定經 pydantic-settings(`.env` 供應 + `SQLALCHEMY_DATABASE_URL` 與 `ANTHROPIC_API_KEY`)。 + 歌詞全文入 DB(不進 git 故無版權疑慮)。 + - 報表:論文引用的最終表由 export 產出 CSV 進 `results/` + ——此為「可再生仍 commit」的唯一例外,理由:引用穩定性 + (十年尺度的環境會腐化)、審稿人零門檻、撰稿期數字變動 + 可 diff。 +- **資料模型**:`songs`(歌曲實體)、`chart_entries` + (1 歌—N 筆榜單紀錄)、`artists`(歌手實體:Wikidata QID、 + 性別、型態、曲風、國籍)、`song_artists`(M—N 關聯:角色、 + 署名順序)、`lyrics`(1—1)。領域不變量(恰 1000 筆榜單、 + 每歌至少一 primary 歌手等)檢查內建於 `build-db`,違規即 + 建置失敗。 +- **歌手背景防火牆**:歌手背景資料只進人工解讀階段(證據表、 + 論文討論),**絕不進 LLM 輸入**——LLM 分類的 user message + 維持歌詞-only,避免光環偏誤污染條件 A/B 實驗。women-power + 候選歌曲的歌手另做深度背景(族裔以公開自我認同為準、音樂 + 場景),script 輔助、人工核定。 +- **Pilot 歌詞沿用**:先導研究捕捉檔(lyrics.json,684 首, + 2018–2025)匯入歌詞快取——只取識別欄位與歌詞本文,pilot + 的分析欄位一律不匯入;以 (year, rank) 精確匹配 song_id。 + 出處記於 `data/lyrics_provenance.csv`(進 git):`source` + (原始 API)與 `method`(pilot-import / api-fetch)兩層, + 取得日期不可考者不假造,僅記可證上界。 +- **子命令**(`pop-fem-audit-tools ` 或 + `python -m pop_fem_audit_tools `):`run-llm`(已完成)、 + `build-db`、`import-lyrics`、`fetch-lyrics`、`fetch-artists`、 + `export-llm-input`;之後再加報表 export 與統計。 + ## 階段與時程(全文截稿 2026-08-15) | 階段 | 內容 | 方式 | 時程 | |---|---|---|---| | 0 | 基礎建設:git init、目錄結構、.gitignore、決策日誌、runner script(含 Batch API)、codebook v0 骨架 | script + 討論 | 7/30–7/31 | -| 1 | 資料準備:去重唯一歌曲表(song id)、抓歌詞(Lyrics.ovh / LRCLIB,缺漏留 log)、演唱者性別表(Wikidata + 人工核對) | scripts | 7/31–8/2 | +| 1 | 資料準備:`run_llm` 改走統一設定 → `build-db`(解析榜單成 songs/chart_entries/artists/song_artists)→ `import-lyrics`(pilot 2018–2025)→ `fetch-lyrics`(2016–17 與缺漏,Lyrics.ovh / LRCLIB)→ `fetch-artists`(Wikidata 快照 + 人工 overrides)→ `export-llm-input` | 子命令 | 7/31–8/3 | | 2 | 候選篩選:全部唯一歌曲高召回 women-power 候選篩選(寧可多抓,人工剔除) | API 2+1 | 8/2–8/3 | | 3 | 黃金標準:依 codebook 人工逐首判定 genuine/peripheral/fake,附引用歌詞證據表(LLM 只做摘錄,不給判定建議);先以 10–15 首校準樣本試編並修訂 codebook 後凍結;同批校準樣本實測 Sonnet 4.6 vs Opus 5 一致率 | 人工 + script 輔助 | 8/4–8/8 | | 4 | 受控比較(盲點實驗):條件 A(詞彙層提示)vs 條件 B(框架感知提示),各 2+1,對照黃金標準計算假陽/假陰率 | API | 8/6–8/9 |