Skip to content

feat(cli): upgrade gate + lifecycle subdirs in run (#404, #410)#414

Merged
MScottAdams merged 1 commit intophase2/vbrief-cutoverfrom
agent1/fix/404-410-run
Apr 16, 2026
Merged

feat(cli): upgrade gate + lifecycle subdirs in run (#404, #410)#414
MScottAdams merged 1 commit intophase2/vbrief-cutoverfrom
agent1/fix/404-410-run

Conversation

@MScottAdams
Copy link
Copy Markdown
Collaborator

Summary

Swarm-402 PR 2/4. Combines #404 and #410 because both touch the single run file; the charter explicitly serializes them into one PR.

#404run project scaffolds vBRIEF lifecycle subdirectories

cmd_project() previously wrote vbrief/PROJECT-DEFINITION.vbrief.json but did not create the 5 lifecycle subdirectories (proposed/, pending/, active/, completed/, cancelled/). The skill-driven greenfield path already creates them (skills/deft-directive-setup/SKILL.md), so the CLI path now matches.

After run project, task vbrief:validate and task scope:* work out-of-the-box without manual folder creation.

A new module-level LIFECYCLE_FOLDERS constant in run mirrors the same tuple in scripts/vbrief_validate.py and scripts/project_render.py; a test asserts they stay in sync.

#410 — version/upgrade gate on deft/run entry

Consumer projects updating their deft/ submodule have no deterministic gate that reminds them to run migration. The sync skill only fires on explicit agent triggers; task check is the consumer's own. deft/run is the one entry point directive controls that runs in consumer project context.

This PR adds a non-fatal version gate before any subcommand dispatch:

  1. On first setup, run project writes a vbrief/.deft-version marker containing the framework VERSION.
  2. On every subsequent invocation, the gate compares the recorded version against VERSION and warns on drift: "Deft has been updated from X to Y. Run deft/run upgrade or task migrate:vbrief to update your project files."
  3. If no marker exists but legacy SPECIFICATION.md / PROJECT.md without the <!-- deft:deprecated-redirect --> sentinel are found, the gate warns about pre-v0.20 state.
  4. Interactive sessions get a Continue anyway? [y/N] prompt; non-interactive sessions (CI, cloud agents) warn once and continue per the swarm-402 charter ("never fatal").
  5. The gate is skipped inside the deft framework repo itself (heuristic: root main.md present, no ./deft/ subdir), so maintainers don't get nagged every invocation.
  6. Commands that never touch project state (help, --help, -h, version, --version, -v, upgrade) are skipped.

A new run upgrade command writes the marker and surfaces legacy-artifact guidance; task migrate:vbrief remains authoritative for the heavy lifting (SPECIFICATION.md / PROJECT.md migration, lifecycle folder creation for existing projects). run upgrade is registered in the dispatcher and listed in usage().

Changes

Validation

Scope & constraints

  • Scope fence respected — only run, the new test module, the two scope vBRIEFs, and CHANGELOG entries are touched.
  • Gate is non-fatal per charter: interactive prompts let the user continue; non-interactive environments never exit early.
  • No force-push, no changes to base branch, no new files outside enumerated scope.

Part of #402 pre-merge must-fix batch

PR 2 of 4 in the swarm-402 cascade on phase2/vbrief-cutover. Previous: #413 (#405). Next will target #407 + #408 (README + BROWNFIELD.md).

Closes #404
Closes #410
Refs #402

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 16, 2026

Greptile Summary

This PR combines two related changes: cmd_project now scaffolds the five vbrief/ lifecycle subdirectories and writes a .deft-version marker on first setup (#404), and a non-fatal version/upgrade gate is added before every subcommand dispatch in main() (#410). The implementation is well-structured with 23 new tests covering the gate, helpers, cmd_upgrade, and lifecycle scaffolding; previously flagged issues (OSError fallback, hardcoded constant comparison, pre-v0.20 detection on projects without vbrief/) appear addressed in this revision.

Confidence Score: 5/5

Safe to merge — all previously flagged issues are addressed and only trivial dead-code style findings remain.

The three concerns from earlier review threads (OSError fallback silently dropped, hardcoded constant comparison, pre-v0.20 detection skipped when no vbrief/ dir) are all resolved in this revision. The two new findings are dead-variable / dead-function style issues with zero behavioral impact. Test coverage is thorough (23 tests, including a regression test for the canonical v0.19 layout). Score 5 because every remaining finding is P2.

No files require special attention — the two minor style nits are in run (line 592) and tests/cli/test_upgrade_gate.py (line 222).

Important Files Changed

Filename Overview
run Adds upgrade gate helpers, cmd_upgrade, lifecycle subdir scaffolding in cmd_project, and gate wiring in main(); one dead variable left over in _check_upgrade_gate
tests/cli/test_upgrade_gate.py 23 well-structured tests covering all new code paths; one dead inner function _isatty_patch in the _stdin_tty helper
CHANGELOG.md Adds entries for #404 and #410 under [Unreleased]; no issues
vbrief/active/2026-04-16-404-run-project-lifecycle-subdirs.vbrief.json Scope vBRIEF for #404; no code issues
vbrief/active/2026-04-16-410-run-upgrade-gate.vbrief.json Scope vBRIEF for #410; no code issues

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["deft/run <command>"] --> B{TUI / no-args?}
    B -- yes --> C["Launch TUI / show usage"]
    B -- no --> D{help / -h / --help?}
    D -- yes --> E["usage() → exit 0"]
    D -- no --> F["_check_upgrade_gate(command)"]

    F --> G{command in SKIP_COMMANDS?}
    G -- yes --> H["return True (skip)"]
    G -- no --> I{_running_inside_deft_repo?}
    I -- yes --> H
    I -- no --> J["_read_version_marker()"]

    J --> K{marker found?}
    K -- "yes, matches VERSION" --> H
    K -- "yes, drift" --> L["warn: version drift"]
    K -- no --> M["_detect_pre_cutover_legacy()"]
    M --> N{legacy artifacts?}
    N -- none --> H
    N -- found --> O["warn: Pre-v0.20"]

    L --> P{sys.stdin.isatty?}
    O --> P
    P -- no --> H
    P -- yes --> Q["read_yn: Continue anyway? y/N"]
    Q -- yes --> H
    Q -- no --> R["warn + return False → exit 1"]

    H --> S["dispatch command"]
    S --> T{cmd_project}
    S --> U{cmd_upgrade}

    T --> V["_atomic_write PROJECT-DEFINITION.vbrief.json"]
    V --> W["mkdir lifecycle folders"]
    W --> X["_write_version_marker vbrief/.deft-version"]

    U --> Y{vbrief/ exists?}
    Y -- yes --> Z["_write_version_marker vbrief/.deft-version"]
    Y -- no --> AA["_write_version_marker project_root/.deft-version"]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: run
Line: 592

Comment:
**Dead variable `vbrief_dir`**

`vbrief_dir` is assigned but never referenced again inside `_check_upgrade_gate`. It appears to be a leftover from an earlier revision where the function had an early return guarded on `vbrief_dir.is_dir()`. Safe to remove.

```suggestion

```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: tests/cli/test_upgrade_gate.py
Line: 222-223

Comment:
**Dead inner function `_isatty_patch`**

`_isatty_patch` is defined but never called; the `lambda: value` on line 227 does all the actual patching. The inner function can be removed without changing any test behavior.

```suggestion
        # Patch isatty on both the attribute and the function
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (4): Last reviewed commit: "feat(cli): upgrade gate + lifecycle subd..." | Re-trigger Greptile

Comment thread run Outdated
Comment thread tests/cli/test_upgrade_gate.py
@MScottAdams MScottAdams force-pushed the agent1/fix/404-410-run branch 2 times, most recently from b243412 to fd5054d Compare April 16, 2026 23:28
Comment thread run Outdated
- #404: `run project` now scaffolds the 5 vBRIEF lifecycle subdirectories
  (proposed/, pending/, active/, completed/, cancelled/) immediately after
  writing PROJECT-DEFINITION.vbrief.json, matching the skill-driven
  greenfield path so `task vbrief:validate` and `task scope:*` work
  out-of-the-box. A module-level LIFECYCLE_FOLDERS constant is shared
  between cmd_project and future callers.
- #410: add a non-fatal version/upgrade gate at `deft/run` entry. On every
  invocation, compare the recorded framework version in
  vbrief/.deft-version (fallback: ./.deft-version) against VERSION and
  warn on drift, directing users to `deft/run upgrade` or
  `task migrate:vbrief`. Detect pre-v0.20 legacy artifacts (SPECIFICATION.md
  or PROJECT.md without the <!-- deft:deprecated-redirect --> sentinel)
  and warn even if no marker exists. Interactive sessions get a
  "Continue anyway? [y/N]" prompt; non-interactive sessions warn and
  continue so CI never breaks. Skip entirely when running inside the
  deft framework repo itself (detected by root main.md + missing ./deft/).
- Add `run upgrade` command: records the current VERSION in
  vbrief/.deft-version, surfaces legacy-artifact guidance, and is
  idempotent when the marker already matches.
- `run project` writes the marker on successful first-setup so the gate
  stays silent on subsequent invocations of a freshly-configured project.
- Register `upgrade` in the command dispatcher and usage() listings.
- Add scope vBRIEFs 2026-04-16-404-run-project-lifecycle-subdirs.vbrief.json
  and 2026-04-16-410-run-upgrade-gate.vbrief.json with origin provenance.
- CHANGELOG entries under [Unreleased].
- 23 new tests in tests/cli/test_upgrade_gate.py covering marker
  round-trips, legacy detection, deft-repo heuristic, gate behavior
  (silent match, warn on drift, non-interactive continues, skip
  commands), cmd_upgrade flows, and the #404 lifecycle subdir scaffolding.

Closes #404
Closes #410
Part of #402
@MScottAdams MScottAdams force-pushed the agent1/fix/404-410-run branch from fd5054d to 9848b03 Compare April 16, 2026 23:38
@MScottAdams
Copy link
Copy Markdown
Collaborator Author

Acknowledging the two remaining P2 findings (confidence now 5/5):

  1. run line 592 — dead vbrief_dir local in _check_upgrade_gate. Real; accurate residue from the earlier revision.
  2. tests/cli/test_upgrade_gate.py line 222 — dead _isatty_patch inner function in the _stdin_tty helper. Real.

Not fixing in this PR per the swarm-402 charter severity ladder — P2 style findings are non-blocking and a force-push to clean dead lines would cost another ~5-7 min Greptile re-review on an already-5/5 batch. Both will be swept up in a follow-up discovered-during-402 cleanup after the #402 merge gate.

All required checks green (Python CI, Go CI, Greptile Review). All PO Pre-Approval conditions on #402 satisfied (confidence > 3, no P0/P1, CI green, all Greptile comments addressed or acknowledged, no other reviewers with unresolved comments). Proceeding to self-merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant