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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to TangleClaw are documented in this file.

## [Unreleased]

### Fixed

- **Recover global rules from #234 + #236 silently clobbered by CLAUDE.md regeneration (#240)** — `lib/engines.js#_generateClaudeMd` regenerates `CLAUDE.md` from the DB-stored global rules on every session launch / engine PATCH / startup sync, overwriting the on-disk file in place. PR-driven raw-file edits to `CLAUDE.md` (e.g. via `git`) are silently discarded the next time TC restarts — the content lives on in `git log` but is functionally absent from the live ruleset. Two PRs this session were affected: **#234** (the versioning bump-level decision table) and **#236** (the stale-plan archive rule + `gh issue view <N> --json state` issue-state check). Both rule blocks were clobbered after the first TC restart following each merge; the celebrated "structural lessons codified in CLAUDE.md" claim in those PR descriptions was technically true in git history and functionally false in the running ruleset. **Recovery procedure run this session:** read the live DB content via `store.globalRules.load()`, splice the two missing rule blocks back into their respective sections (`Build Plans & Chunks` for #236, `Releases & Versioning` for #234) preserving sibling content, write back via `store.globalRules.save(merged)` (which normalizes and persists to `_globalRulesPath()`). Verified end-to-end: the regenerated `CLAUDE.md` is now byte-for-byte identical to HEAD (diff is empty), so the next TC restart produces no surprise drift. **Defensive comment added** to `lib/engines.js#_generateClaudeMd` documenting the regeneration contract and pointing future readers (or automated agents tempted to commit directly to `CLAUDE.md`) at the durable edit paths: landing-page editor, `PUT /api/rules/global` (10 KB body cap), or `store.globalRules.save()` from a node script. The same regeneration pattern applies to Codex / Aider / Gemini config files — same trap, less commonly hit because TC-v3 itself uses Claude. Public diagnostic + recovery procedure for any other cloner who is affected is documented in #240. Structural fix (preventing the trap from ever firing again — likely either a tracked-file canonical source with startup sync, or an append-only marker pattern that regeneration preserves) is tracked in #240 as separate work.

### Changed

- **"Run Critic" button: clarify the contract via label + confirm dialog + toast (#230)** — the methodology-action button on prawduct projects was previously labeled `Run Critic` with `confirm: false`, so clicking it skipped any dialog and silently POSTed to `/api/projects/:name/actions/invoke-critic`. The handler only appends an entry to `.tangleclaw/critic-runs.json`; it never *runs* a Critic. New operators clicked the button expecting an automated review, saw the toast `Run Critic: recorded`, and reasonably concluded the button was broken (it wasn't — the contract was mislabeled). **What changed.** (1) Label renamed `Run Critic` → `Mark Critic Run` (`data/templates/prawduct/template.json:106`) so the imperative is honest about what the click does. (2) `confirm: false` → `confirm: true` so the contract-clarifying dialog actually fires. (3) Two new optional per-action wording fields added to the methodology template schema — `confirmMessage` and `successToast` — used by `public/session.js#invokeMethodologyAction` when present, falling back to the generic `Run "<label>" for this project?` / `<label>: recorded` when absent. (4) The Critic action's `confirmMessage` reads: *"Confirm an Independent Critic review was completed for this branch. This button does NOT run a Critic automatically — it records that you (or a separate review agent) have completed one, so the wrap step's critic-check passes. Continue?"* — addressing the misread head-on. (5) Its `successToast` reads: *"Critic review recorded for this branch"*. **API surface change.** `lib/projects.js:enrichProject` (line 602 region) extends the methodology-action allow-list to surface `confirmMessage` and `successToast` when present and non-empty; absent fields stay absent (the handler's `typeof === 'string' && length > 0` guard tolerates both shapes). Per `feedback_symmetric_capability_gates`, the inline comment now documents that the allow-list is intentionally restrictive and lists every field it exposes. **Tests.** `test/api-actions.test.js`'s `prawduct project response includes actions[]` case extended from 2 assertions to 7: label is the new value, confirm flipped to true, confirmMessage and successToast are present-and-non-empty strings on the wire. Other test files that reference `Run Critic` as a fixture string (e.g. `test/store.test.js:896-1402`) are not load-bearing for the rename — they test store-layer merge logic against synthetic data, not the prawduct template — so they're left alone. Full suite 2445/2446 pass (1 pre-existing skip on this case-insensitive host). Closes #230.
Expand Down
26 changes: 26 additions & 0 deletions lib/engines.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,32 @@ function _getRulesContent(projectConfig) {

/**
* Generate CLAUDE.md content for Claude Code.
*
* **⚠ Regeneration is destructive (#240).** This function is the sole
* authority for `CLAUDE.md` content. It runs on every session launch
* (`lib/sessions.js#launchSession`), on engine/methodology PATCH
* (`lib/projects.js#updateProject`), and on startup sync
* (`lib/projects.js#syncAllProjects`). The resulting file is
* **overwritten in place** — there is no merge with any on-disk
* edits. Manual edits to `CLAUDE.md` (or PR-driven raw-file edits
* via `git`) are silently discarded the next time TC regenerates.
*
* To add or change global rules durably:
* - Edit via the landing-page gear icon → Global Rules editor
* - Or `PUT /api/rules/global` (10 KB body cap)
* - Or call `store.globalRules.save(content)` from a node script
* (no body-size limit; bypasses the API parser)
*
* Both PR-driven approaches land the content in the DB-stored global
* rules file (`store.globalRules.load() / .save()`), which this
* function reads via `_getRulesContent`. Bypassing the DB and
* committing directly to `CLAUDE.md` makes the change visible in
* `git log` but functionally absent — see #240 for the diagnosis +
* recovery procedure.
*
* The same regeneration pattern applies to `_generateCodexYaml`,
* `_generateAiderConf`, and `_generateGeminiMd` below.
*
* @param {object} projectConfig - Per-project config
* @param {object} [methodologyTemplate] - Methodology template
* @returns {string}
Expand Down