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 .edpa/engine/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.19.0
2.20.0
3 changes: 2 additions & 1 deletion .edpa/engine/scripts/hooks/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# the documented `sh .edpa/engine/scripts/hooks/install.sh` path.
#
# It installs into .git/hooks/ (ownership-tracked, foreign hooks left alone)
# or prints a paste-ready snippet when lefthook is detected. The old
# or, when lefthook is detected, wires one `extends:` line into the lefthook
# config — the only edit EDPA makes to that file. The old
# `git config core.hooksPath` mechanism is gone: it pointed at a stale path
# and silently fought lefthook / the .git/hooks/ copy path.
ROOT="$(git rev-parse --show-toplevel 2>/dev/null)"
Expand Down
2 changes: 1 addition & 1 deletion .edpa/engine/scripts/hooks/pre-commit-id-safety
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Layer 5 from docs/v2/plan.md.
#
# Install: /edpa:setup --with-hooks (or project_setup.py --with-hooks). Detects
# lefthook and prints a paste-ready snippet instead of writing .git/hooks/.
# lefthook and wires an `extends:` line into its config instead of .git/hooks/.
#
# Exit 1 to block commit on any ID safety violation.

Expand Down
2 changes: 1 addition & 1 deletion .edpa/engine/templates/edpa.yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ project:

governance:
# Auto-stamped to the installed plugin version by install.sh / project_setup.py.
methodology: "EDPA 2.19.0"
methodology: "EDPA 2.20.0"
# v1.14: single calculation path. v1.17: yaml_edit signals — every
# commit on .edpa/backlog/<typ>/<id>.md contributes structural credit
# (create / block_add / list_grow / scalar_change / lines_volume /
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog

## Unreleased
## 2.20.0 — 2026-07-20

Lefthook `extends:` becomes the default registration path — EDPA wires it
itself — plus the hook self-heal deadlock that stopped `/plugin update` from
delivering hook fixes at all.

### Fixed

Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**Derive hours from Git evidence. No timesheets.**

[![EDPA](https://img.shields.io/badge/EDPA-2.19.0-34d399)](docs/methodology.md)
[![EDPA](https://img.shields.io/badge/EDPA-2.20.0-34d399)](docs/methodology.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![GitHub](https://img.shields.io/badge/Made_for-GitHub-181717?logo=github)](https://github.com)

Expand All @@ -29,7 +29,7 @@ Monday morning: "What did I work on last week? Let me guess... 4h on S-200, mayb
```
$ python3 .edpa/engine/scripts/engine.py --edpa-root .edpa --iteration PI-2026-1.3

EDPA 2.19.0 — Iteration PI-2026-1.3
EDPA 2.20.0 — Iteration PI-2026-1.3
======================================================================
Person Role Capacity Derived Items OK
----------------------------------------------------------------------
Expand All @@ -50,7 +50,7 @@ All invariants passed: YES

## Key Features

- **Zero manual input** — hours derived from **local git evidence**: post-commit hook emits `commit_author` + `/contribute` signals; engine reads `yaml_edit`, gate-event, and in-flight Story activity directly from `git log`. Hooks register into `.git/hooks/` (or, under lefthook, via a printed snippet) and can be verified with `project_setup.py --check-hooks`.
- **Zero manual input** — hours derived from **local git evidence**: post-commit hook emits `commit_author` + `/contribute` signals; engine reads `yaml_edit`, gate-event, and in-flight Story activity directly from `git log`. Hooks register into `.git/hooks/` (or, under lefthook, via a single `extends:` line EDPA writes into your lefthook config and nothing else) and can be verified with `project_setup.py --check-hooks`.
- **Mathematical guarantee** — derived hours always sum to declared capacity
- **Gates mode (default)** — credits each Initiative/Epic/Feature status transition as a mini-deliverable, so prep work (LBC, decomposition, design) gets credited as it happens, not only at final Done. Validated to ±0.35 pp stability under ±20 % CW perturbation across 100 Monte Carlo runs.
- **C7.5 in-flight Story credit** — Stories with `yaml_edit` activity in the iteration window receive partial credit (`js × credit_factor`, default 0.40) even before they reach Done; the `story_activity_events[]` audit log in `edpa_results.json` records what was credited and why.
Expand Down Expand Up @@ -94,7 +94,7 @@ Bootstrapping .edpa/ data tree...
Created .edpa/config/people.yaml (edit with your team)
Created .edpa/config/edpa.yaml (edit project.name + governance metadata)

EDPA 2.19.0 installed.
EDPA 2.20.0 installed.
```

The installer vendors the engine to `.edpa/engine/` (it installs no pip
Expand Down Expand Up @@ -137,7 +137,7 @@ python3 .edpa/engine/scripts/engine.py --status
```

```
EDPA 2.19.0 — Status
EDPA 2.20.0 — Status
========================================
✓ .edpa/ found at .edpa
✓ people.yaml — 2 members, 1.5 FTE, 60h/iteration
Expand Down Expand Up @@ -221,7 +221,7 @@ Snapshot frozen: .edpa/snapshots/PI-2026-1.1.json
Excel: .edpa/reports/iteration-PI-2026-1.1/edpa-results.xlsx

======================================================================
EDPA 2.19.0 — Iteration PI-2026-1.1
EDPA 2.20.0 — Iteration PI-2026-1.1
======================================================================
Person Role Capacity Derived Items OK
----------------------------------------------------------------------
Expand Down Expand Up @@ -449,7 +449,7 @@ python3 .edpa/engine/scripts/backlog.py add --type Story --title "..."

| Document | Description |
|----------|-------------|
| [Methodology](docs/methodology.md) | Full EDPA v2.19.0 specification |
| [Methodology](docs/methodology.md) | Full EDPA v2.20.0 specification |
| [Quick Start](docs/quick-start.md) | 10-minute setup guide |
| [Operational Runbook](docs/RUNBOOK.md) | Every `/edpa:*` command end to end — setup, close-iteration, capacity, autocalib, board |
| [Playbook](docs/playbook.md) | From empty repo to first closed PI — full operations guide (Czech) |
Expand Down
21 changes: 14 additions & 7 deletions docs/RUNBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ engine + `.edpa/` tree.
**Expected output (last steps):**

```
[1] Vendor engine ✓ Vendored engine → .edpa/engine/ (49 scripts, VERSION 2.19.0)
[1] Vendor engine ✓ Vendored engine → .edpa/engine/ (49 scripts, VERSION 2.20.0)
[2] Directory tree ✓ Directory tree at .edpa/
[3] Config templates ✓ Seeded people.yaml, edpa.yaml, cw_heuristics.yaml
[4] ID counter ✓ id_counters.yaml seeded
Expand All @@ -110,7 +110,7 @@ EDPA setup complete.
hand-edit; the SessionStart hook re-syncs it on plugin update).
- `.edpa/config/{edpa.yaml,people.yaml,cw_heuristics.yaml,id_counters.yaml}`.
- `.edpa/{backlog,iterations,reports,snapshots}/` tree.
- (flags) `.git/hooks/*` (or a lefthook snippet),
- (flags) `.git/hooks/*` (or one `extends:` line in your lefthook config),
`.github/workflows/edpa-contribution-sync.yml`, `.claude/rules/`.

**Git hooks — registration, lefthook, verification:**
Expand All @@ -132,17 +132,24 @@ deliberately careful:
dispatcher shims into `.git/hooks/` (and can set `core.hooksPath`), so a plain
copy would be ignored or clobbered — this is the usual cause of "contribution
stopped working after an update". EDPA detects `lefthook.yml` and, instead of
writing `.git/hooks/`, EDPA registers via lefthook. **Recommended** — add one
line pointing at the vendored fragment, then run `lefthook install`; it tracks
plugin updates automatically (no re-paste):
writing `.git/hooks/`, registers via lefthook — it **writes this one line into
your lefthook config itself**, then you run `lefthook install`:

```yaml
extends:
- .edpa/engine/lefthook-edpa.yml
```

Or paste the full block as a fallback (no auto-propagation), then
`lefthook install`:
That entry is the **only** thing EDPA ever changes in a lefthook config —
nothing removed, reordered or reformatted, and a stale hand-pasted EDPA block
is left in place on purpose (harmless: the fragment wins the command-name
collision and its `run:` lines are identical). Because the fragment is
re-vendored every session, hook fixes then arrive with `/plugin update`
instead of needing a re-paste, and a repo still on a pasted block is migrated
onto `extends:` automatically at the next update.

A `lefthook.toml`/`.json` cannot be line-edited safely, so those get the full
block printed to paste by hand (no auto-propagation), then `lefthook install`:

```yaml
pre-commit:
Expand Down
2 changes: 1 addition & 1 deletion docs/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ read + write access to `.edpa/` project data — config, iterations, people,
backlog — over the standard MCP `stdio` transport. Any MCP-aware client
(Claude Code, Cursor, Codex CLI, custom Python/TS clients) can use it.

**Production-ready since v1.3.0-beta; current as of v2.19.0** (read + write
**Production-ready since v1.3.0-beta; current as of v2.20.0** (read + write
tools — see the tool tables below). Validated handlers, schema-checked
inputs, item-ID path-traversal guard, stderr logging, version-aware identity.

Expand Down
2 changes: 1 addition & 1 deletion docs/methodology.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

*Capacity derivation from delivery evidence*

**Version 2.19.0 — July 2026 — Jaroslav Urbanek, Lead Architect**
**Version 2.20.0 — July 2026 — Jaroslav Urbanek, Lead Architect**

---

Expand Down
8 changes: 4 additions & 4 deletions docs/playbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Kompletni prirucka pro nasazeni metodiky EDPA (Evidence-Driven Proportional Allo

EDPA V2 je **local-first**: zdrojem pravdy je `.edpa/backlog/**/*.md` (YAML frontmatter), git je audit trail. GitHub je **volitelny** -- zadny GitHub Project, zadne org Issue Types, zadny obousmerny sync.

**Verze:** EDPA 2.19.0
**Posledni aktualizace:** 2026-07-19
**Verze:** EDPA 2.20.0
**Posledni aktualizace:** 2026-07-20

---

Expand Down Expand Up @@ -78,7 +78,7 @@ V terminalu s Claude Code nainstalovanym:
/edpa:setup --with-ci --with-hooks --with-rules
```

Claude Code (skill `/edpa:setup`) provede kroky 1.1-1.4 automaticky -- vendoruje engine do `.edpa/engine/`, naseje konfiguraci a `id_counters.yaml`, a volitelne nainstaluje git hooky, PR-signal CI workflow a `.claude/rules/`. Idempotentni -- opakovane spusteni nic nerozbije. `--with-hooks` je lefthook-aware (pri pritomnem `lefthook.yml` vypise snippet misto zapisu do `.git/hooks/`); stav overis pres `--check-hooks`.
Claude Code (skill `/edpa:setup`) provede kroky 1.1-1.4 automaticky -- vendoruje engine do `.edpa/engine/`, naseje konfiguraci a `id_counters.yaml`, a volitelne nainstaluje git hooky, PR-signal CI workflow a `.claude/rules/`. Idempotentni -- opakovane spusteni nic nerozbije. `--with-hooks` je lefthook-aware (pri pritomnem `lefthook.yml` zapise jediny radek `extends: .edpa/engine/lefthook-edpa.yml` misto zapisu do `.git/hooks/`); stav overis pres `--check-hooks`.

### Cesta B: Manualni CLI

Expand Down Expand Up @@ -207,7 +207,7 @@ project:

governance:
# Auto-razitkovano na verzi pluginu instalatorem.
methodology: "EDPA 2.19.0"
methodology: "EDPA 2.20.0"
# Jedina vypocetni cesta od v1.14 (zadny simple/full/gates mode selector,
# zadny audit_mode -- snapshoty vzdy nesou plny signals[] audit trail).

Expand Down
7 changes: 4 additions & 3 deletions docs/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,10 @@ If your team has more than one person creating backlog items in parallel, you'll

```bash
# 1. Install git hooks (pre-commit, pre-push, commit-msg, post-commit).
# Under lefthook this prints a snippet to paste into lefthook.yml + run
# `lefthook install` instead of writing .git/hooks/. Foreign hooks are
# never overwritten; re-run any time to refresh.
# Under lefthook this writes one `extends:` line into lefthook.yml (and
# nothing else there) instead of writing .git/hooks/ — then run
# `lefthook install`. Foreign hooks are never overwritten; re-run any
# time to refresh.
python3 .edpa/engine/scripts/project_setup.py --with-hooks
python3 .edpa/engine/scripts/project_setup.py --check-hooks # verify (read-only)

Expand Down
2 changes: 1 addition & 1 deletion plugin/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "edpa",
"version": "2.19.0",
"version": "2.20.0",
"description": "EDPA — Evidence-Driven Proportional Allocation. Derive hours from local git evidence (commits, yaml edits, status transitions). Zero timesheets, mathematical guarantee, Monte Carlo calibrated CW weights. Local-first: .edpa/backlog/ YAML as source of truth, git as the audit trail. GitHub Projects sync optional.",
"author": {
"name": "TECHNOMATON",
Expand Down
3 changes: 2 additions & 1 deletion plugin/edpa/scripts/hooks/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# the documented `sh .edpa/engine/scripts/hooks/install.sh` path.
#
# It installs into .git/hooks/ (ownership-tracked, foreign hooks left alone)
# or prints a paste-ready snippet when lefthook is detected. The old
# or, when lefthook is detected, wires one `extends:` line into the lefthook
# config — the only edit EDPA makes to that file. The old
# `git config core.hooksPath` mechanism is gone: it pointed at a stale path
# and silently fought lefthook / the .git/hooks/ copy path.
ROOT="$(git rev-parse --show-toplevel 2>/dev/null)"
Expand Down
2 changes: 1 addition & 1 deletion plugin/edpa/scripts/hooks/pre-commit-id-safety
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Layer 5 from docs/v2/plan.md.
#
# Install: /edpa:setup --with-hooks (or project_setup.py --with-hooks). Detects
# lefthook and prints a paste-ready snippet instead of writing .git/hooks/.
# lefthook and wires an `extends:` line into its config instead of .git/hooks/.
#
# Exit 1 to block commit on any ID safety violation.

Expand Down
2 changes: 1 addition & 1 deletion plugin/edpa/templates/edpa.yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ project:

governance:
# Auto-stamped to the installed plugin version by install.sh / project_setup.py.
methodology: "EDPA 2.19.0"
methodology: "EDPA 2.20.0"
# v1.14: single calculation path. v1.17: yaml_edit signals — every
# commit on .edpa/backlog/<typ>/<id>.md contributes structural credit
# (create / block_add / list_grow / scalar_change / lines_volume /
Expand Down
4 changes: 2 additions & 2 deletions web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "edpa-web",
"type": "module",
"version": "2.19.0",
"version": "2.20.0",
"private": true,
"scripts": {
"dev": "astro dev",
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/en/guide.astro
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ python3 .edpa/engine/scripts/setup.py --with-ci`,
→ PR-thread signals → evidence[] on items
✓ Git hooks installed (commit-msg: feat(<ID>): …)
# Under lefthook (lefthook.yml present): EDPA does not write .git/hooks/,
# it prints a snippet → paste into lefthook.yml and run: lefthook install
# it writes one extends: line into lefthook.yml → then run: lefthook install
# Verify anytime: project_setup.py --check-hooks

# Local-first: no org, no PAT, no GitHub Projects.`,
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/en/methodology.astro
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ Accuracy = Actual / Planned &times; 100 %</div>
</div>

<h3>9.2 The engine runs locally; the GitHub layer is optional</h3>
<p>V2 has no GitHub Actions pipeline. The engine, WSJF computation, iteration/PI close, and velocity all run <strong>locally</strong> via <code>/edpa:close-iteration</code> and MCP tools. Attribution is handled by a post-commit hook (<code>local_evidence.py</code>) — it emits <code>commit_author</code> for every commit that references an EDPA item, and works offline and on GitLab/Forgejo too. Hooks register into <code>.git/hooks/</code>, or — if the project uses lefthook — via a printed snippet for <code>lefthook.yml</code>.</p>
<p>V2 has no GitHub Actions pipeline. The engine, WSJF computation, iteration/PI close, and velocity all run <strong>locally</strong> via <code>/edpa:close-iteration</code> and MCP tools. Attribution is handled by a post-commit hook (<code>local_evidence.py</code>) — it emits <code>commit_author</code> for every commit that references an EDPA item, and works offline and on GitLab/Forgejo too. Hooks register into <code>.git/hooks/</code>, or — if the project uses lefthook — via a single <code>extends:</code> line EDPA writes into <code>lefthook.yml</code> itself.</p>
<div class="card">
<table>
<thead>
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/en/playbook.astro
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ git checkout -b chore/T-050-ci-pipeline</code></pre>
<p>Hook registration is idempotent and self-refreshing (the SessionStart auto-update re-registers them after a plugin update). Foreign (non-EDPA) hooks are never clobbered — they are skipped with a warning. Check hook state (active / missing / foreign / lefthook) anytime with the read-only doctor:</p>
<pre><code>python3 .edpa/engine/scripts/project_setup.py --check-hooks
python3 .edpa/engine/scripts/project_setup.py --refresh-hooks # register only</code></pre>
<div class="note"><strong>lefthook:</strong> if the project uses <code>lefthook.yml</code> (lefthook owns <code>.git/hooks/</code>), EDPA does <strong>not</strong> write <code>.git/hooks/</code> — instead it prints a paste-ready snippet to add to <code>lefthook.yml</code>, then run <code>lefthook install</code>. Note: <code>pre-push</code> must have <code>use_stdin: true</code> or lefthook hangs.</div>
<div class="note"><strong>lefthook:</strong> if the project uses <code>lefthook.yml</code> (lefthook owns <code>.git/hooks/</code>), EDPA does <strong>not</strong> write <code>.git/hooks/</code> — instead it wires a single <code>extends: .edpa/engine/lefthook-edpa.yml</code> line into <code>lefthook.yml</code>, then run <code>lefthook install</code>. That line is the only thing EDPA ever changes in your lefthook config; an older hand-pasted block is left alone. This is what makes hook fixes arrive with <code>/plugin update</code>. Note: <code>pre-push</code> must have <code>use_stdin: true</code> or lefthook hangs — the fragment sets it.</div>
<pre><code>pre-commit:
commands:
edpa-id-safety:
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/en/setup.astro
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ import Layout from '../../layouts/Layout.astro';
</div>

<div class="form-card launch-note">
<p class="launch-note-text"><code>--with-hooks</code> registers 4 git hooks (pre-commit, commit-msg, post-commit, pre-push) into <code>.git/hooks/</code>. Registration is idempotent and foreign hooks are never clobbered. If the project uses <strong>lefthook</strong> (<code>lefthook.yml</code> owns <code>.git/hooks/</code>), EDPA instead prints a paste-ready snippet — add it to <code>lefthook.yml</code> and run <code>lefthook install</code>. Check hook state anytime with <code>project_setup.py --check-hooks</code>.</p>
<p class="launch-note-text"><code>--with-hooks</code> registers 4 git hooks (pre-commit, commit-msg, post-commit, pre-push) into <code>.git/hooks/</code>. Registration is idempotent and foreign hooks are never clobbered. If the project uses <strong>lefthook</strong> (<code>lefthook.yml</code> owns <code>.git/hooks/</code>), EDPA instead writes a single <code>extends: .edpa/engine/lefthook-edpa.yml</code> line into <code>lefthook.yml</code> and changes nothing else in that file — then run <code>lefthook install</code>. Check hook state anytime with <code>project_setup.py --check-hooks</code>.</p>
<pre class="launch-pre">pre-commit:
commands:
edpa-id-safety:
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/guide.astro
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ python3 .edpa/engine/scripts/setup.py --with-ci`,
→ PR-thread signály → evidence[] na items
✓ Git hooks installed (commit-msg: feat(<ID>): …)
# Pod lefthookem (lefthook.yml přítomen): EDPA nepíše do .git/hooks/,
# ale vytiskne snippet → vlož do lefthook.yml a spusť: lefthook install
# ale zapíše jeden řádek extends: do lefthook.yml → pak: lefthook install
# Ověření kdykoli: project_setup.py --check-hooks

# Local-first: žádný org, žádný PAT, žádné GitHub Projects.`,
Expand Down
Loading
Loading