Skip to content

Fix #880: gitignore .architect-role.md and add update-time backfill - #881

Merged
amrmelsayed merged 6 commits into
mainfrom
builder/bugfix-880
May 27, 2026
Merged

Fix #880: gitignore .architect-role.md and add update-time backfill#881
amrmelsayed merged 6 commits into
mainfrom
builder/bugfix-880

Conversation

@amrmelsayed

Copy link
Copy Markdown
Collaborator

Summary

Every fresh codev init / codev adopt left a dirty git status the first time the architect spawned — Tower writes .architect-role.md to the workspace root, but the file was missing from CODEV_GITIGNORE_ENTRIES. This PR plugs the day-one gap and adds an update-time backfill so existing Codev projects also self-heal.

Fixes#880

Root Cause

packages/codev/src/lib/scaffold.ts declared the codev-managed gitignore block but omitted .architect-role.md. Sibling builder-runtime files (.builder-role.md, etc.) lived under .builders/<id>/ and were covered transitively, but .architect-role.md lives at workspace root with no ignored ancestor. codev update had no gitignore handling at all, so existing projects had no upgrade path either.

Fix

Part 1 — fresh projects: one-line addition to CODEV_GITIGNORE_ENTRIES. Propagates through FULL_GITIGNORE_CONTENT (init) and the direct append (adopt).

Part 2 — existing projects: new backfillGitignore(targetDir, block, options) in scaffold.ts, wired into codev update.

  • Append-only line-level merge — never deletes, reorders, or duplicates.
  • Idempotent: a second invocation after a clean state is a no-op.
  • Compares on trimmed line equality (avoids false-positive substring matches).
  • Missing entries are appended together under # Codev (added by codev update YYYY-MM-DD) so the user can see where they came from.
  • Skips silently if no .gitignore exists — creation belongs to init/adopt.
  • Honors --dry-run.
  • Result surfaced on UpdateResult as gitignoreAdded / gitignoreSkipped; summary line printed in both interactive and agent modes.

Per the issue scope decision, the helper is gitignore-specific (not generalized to a managed-block primitive) — no second use case yet, no premature abstraction.

Test Plan

  • Regression tests added (scaffold.test.tsbackfillGitignore block: append, idempotency, custom-entry preservation, dry-run, skip-when-absent, no-duplicates)
  • init.test.ts and adopt.test.ts assert .architect-role.md appears in fresh project gitignores
  • update.test.ts integration tests for backfill (stale gitignore, dry-run, absent gitignore, idempotent across two updates)
  • tsc clean
  • Full test suite: 3185 passed | 13 skipped (3198)
  • porch check passes both build and tests

Part 1: Add `.architect-role.md` to `CODEV_GITIGNORE_ENTRIES` so fresh
`codev init` and `codev adopt` projects ignore the architect role file
that Tower writes on every architect spawn.
Part 2: Add `backfillGitignore(targetDir, block)` helper and wire it
into `codev update` so existing projects self-heal on next update.
Idempotent, append-only, preserves user entries. Missing entries are
appended together under a `# Codev (added by codev update YYYY-MM-DD)`
header. Skips silently if no .gitignore exists (creation belongs to
init/adopt). Honors --dry-run.
Tests: scaffold.test.ts adds a backfillGitignore describe block
(append, idempotency, custom-entry preservation, dry-run, skip-when-
absent, no-duplicates). init/adopt regression tests verify
`.architect-role.md` appears in fresh gitignores. update.test.ts adds
integration tests for the backfill flow.
…level backfill
Addresses CMAP feedback (codex): the previous short-circuit on
`existing.includes('.agent-farm/')` meant `codev adopt` on a project that
already had a partial Codev block in `.gitignore` (e.g. `.agent-farm/`
ignored but not `.architect-role.md`) would report "already present" and
skip without adding the new entry. That left the bug open for the adopt
path even after Part 1.
`updateGitignore()` now delegates to `backfillGitignore()` for the
exists-branch, giving adopt the same self-healing line-level append that
`codev update` already had. `alreadyPresent: true` now correctly means
all managed entries are present, not just the sentinel.
Tests:
- Replace `scaffold.test.ts` "should not duplicate entries if already
present" — the test was encoding the buggy sentinel behavior. New
version loads the full block and expects `alreadyPresent: true`.
- New regression in `scaffold.test.ts`: partial Codev block → backfilled
without duplicates.
- New regression in `adopt.test.ts`: end-to-end adopt on a project with
partial `.gitignore` adds `.architect-role.md` without duplicating
`.agent-farm/`.
@amrmelsayed

Copy link
Copy Markdown
CollaboratorAuthor

Architect Review

Medium-risk PR (453/9 across 8 files, but only 2 production files — scaffold.ts + update.ts — with the rest being 4 test files + 2 porch bookkeeping). CMAP unanimous (gemini=APPROVE, codex=APPROVE after addressing initial REQUEST_CHANGES on the sentinel bug, claude=APPROVE).

Verified

  • Part 1.architect-role.md added to CODEV_GITIGNORE_ENTRIES. Regression test should include .architect-role.md (issue #880) asserts it stays in. Propagates through FULL_GITIGNORE_CONTENT (init) and the adopt-side append.
  • Part 2backfillGitignore(targetDir, block, options) in scaffold.ts with 6 test cases (append, idempotency, custom-entry preservation, dry-run, skip-when-absent, no-duplicates). Wired into codev update with summary line + result fields on UpdateResult.
  • Codex's catch (iter-2) — solved a real gap: updateGitignore()'s .agent-farm/-as-sentinel short-circuit meant codev adopt on a project with a partial Codev block would skip backfilling. Replaced with delegation to backfillGitignore() so adopt now does line-level merge too. Strictly better than what the issue body proposed — adopt-vs-update path symmetry, both self-heal partial blocks. Worth remembering for future similar primitives: gitignore-style files need line-level discipline, not all-or-nothing sentinels.
  • Test surface complete: scaffold.test.ts (6 backfill cases + CODEV_GITIGNORE_ENTRIES regression), init.test.ts + adopt.test.ts (.architect-role.md presence in fresh gitignores), update.test.ts (backfill integration: stale gitignore, dry-run, absent gitignore, idempotent across two updates). 3185 passed | 13 skipped (3198 total).
  • Third-pattern discipline heldbackfillGitignore stays gitignore-specific per the issue note; not promoted to a generalized backfillManagedBlock helper. Right call for day one.

Notable design improvement

The codex catch closed a defect the issue body didn't anticipate. The original framing assumed updateGitignore was either "fully owned by Codev" or "completely new" — missed the partial-state case where some Codev entries are already present from an older install. Builder's iter-2 fix makes the entire gitignore-management surface (init → adopt → update) consistently line-level append-only, which is the right invariant.

Verdict

Approved. Please merge with: gh pr merge 881 --merge --admin (solo-architect branch-protection workaround).


Architect review

@amrmelsayed
amrmelsayed merged commit fb0bc42 into mainMay 27, 2026
6 checks passed
@amrmelsayed
amrmelsayed deleted the builder/bugfix-880 branch June 20, 2026 00:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant

@amrmelsayed