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
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@ dist/
/site/
/_site/

# gate evidence (pre-GitHub era): curated records live at tag archive/pre-github;
# raw session captures are local-only
# gate evidence (pre-GitHub era) — local-only, never tracked
/gates/
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ pip install -e '.[dev]'
pytest
```

## License & history
## License

Licensed under [Apache-2.0](LICENSE). The pre-GitHub PRD, specs, and phase-gate evidence live at
the git tag `archive/pre-github`.
Licensed under [Apache-2.0](LICENSE).
3 changes: 0 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,3 @@
New capabilities and design changes go through [proposals/](../proposals/README.md) and GitHub
issues. Docs in this directory describe the **current** system; a proposal that lands
updates them in the same PR.

Pre-GitHub history (the PRD, numbered specs 01–15, and phase-gate evidence for Phases 0–29) is
preserved at the git tag `archive/pre-github`.
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ guess, not a proof.

```
src/ea_core/ # the deterministic engine + `ea` CLI
tests/ # unit + e2e contract tests (incl. per-gate e2e suites)
tests/ # unit + e2e contract tests (incl. per-feature e2e suites)
plugins/ # the two adapter surfaces (ea-claude, ea-antigravity)
packs/ # production method packs (open-agile-architecture,
# enterprise-architecture, lean-ux, …)
Expand Down
4 changes: 1 addition & 3 deletions docs/decisions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ Short records of the **still-binding** design decisions whose *why* is not obvio
reference docs — the constraints a future change must either respect or deliberately revisit
(via a [proposal](../../proposals/)).

Historical context: these distill the D1–D41 decision log of the pre-GitHub era PRD. The full
log, the numbered specs, and the phase-gate evidence live in git history at the tag
**`archive/pre-github`**.
Historical context: these distill the D1–D41 decision log of the pre-GitHub era PRD.

| # | Decision |
|---|---|
Expand Down
4 changes: 2 additions & 2 deletions proposals/0001-ea-show.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ Agents inspecting a single artifact today either read the whole file from disk o
`report`/`validate` output to the purpose. There is no read verb that returns one artifact's
front-matter (and body) through the contract, and no way to trim the response to the needed
fields — the read-side `--fields` projection (spec 09; spec numbers, like D-numbers, refer to
the archived pre-GitHub record at `archive/pre-github`) covers the record/key-shaped verbs only.
the archived pre-GitHub record) covers the record/key-shaped verbs only.

Reading files directly costs tokens (the body rides along even when only one field is needed),
bypasses the self-describing not-found contract, and pushes resolution logic (scope
fall-through, layering) onto every surface — a per-host duplication P2 exists to prevent.

The gap was deferred deliberately: D28/D29 (at `archive/pre-github`) kept artifact front-matter
The gap was deferred deliberately: D28/D29 kept artifact front-matter
out of `graph dependency --fields` because inlining it would either break the purely-subtractive
invariant or bloat the default output, and pointed instead at "a purpose-built single-artifact
`ea show --fields`, where trimming front-matter is naturally subtractive". The Phase-19 advisory
Expand Down
2 changes: 1 addition & 1 deletion proposals/0002-validate-warning-dead-renames.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

A manifest `renames:` entry whose `from` names no rule the active set actually renamed is
**silently ignored** at materialization. The overlay maps a pack's published rule id to a local
id (`{pack, kind: rule, from, to}`, decision 0007, D38 at `archive/pre-github`); the mapping is
id (`{pack, kind: rule, from, to}`, decision 0007, D38); the mapping is
consulted only through `materialize.local_rule` while walking selected methods
(`src/ea_core/materialize.py`). An entry that no selected method reaches is never applied and
never reported — the closure just doesn't call `local_rule` with that key.
Expand Down
6 changes: 3 additions & 3 deletions tests/e2e/test_archetype_migrate.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Phase-7 gate (archived at tag archive/pre-github): write-side — ``ea migrate`` (archived at tag archive/pre-github).
"""Write-side — ``ea migrate``.

An existing ``startup-light`` configuration evolves to ``enterprise-heavy`` via a
reviewed, confirmed plan that **preserves prior deliberate choices** and **surfaces
Expand Down Expand Up @@ -29,7 +29,7 @@
ROOT = Path(__file__).resolve().parents[2]

MANIFEST = "ea.manifest.yaml"
INDEX = "definitions/index.yaml" # the pack@version integrity lock (Phase 14)
INDEX = "definitions/index.yaml" # the pack@version integrity lock
NEW_DEFS = [
"definitions/methods/data-modeling.yaml",
"definitions/methods/service-design.yaml",
Expand Down Expand Up @@ -184,7 +184,7 @@ def test_drift_after_plan_is_refused(repo):


def test_migrate_plan_is_byte_stable(repo):
"""Identical inputs → byte-identical stdout (NFR-1)."""
"""Identical inputs → byte-identical stdout (P1)."""
_bootstrap(repo)
_, _, raw1 = run_cli("migrate", "enterprise-heavy")
_, _, raw2 = run_cli("migrate", "enterprise-heavy")
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/test_authoring_flow.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Phase-2 gate (archived at tag archive/pre-github): the exact CLI sequence the plugin drives —
"""The exact CLI sequence the plugin drives —
adopt -> scaffold -> commit x2 -> validate — via the direct contract.
"""

Expand Down Expand Up @@ -126,7 +126,7 @@ def test_commit_drift_guard_refuses_bad_token(repo):
assert code == 4 and bad["status"] == "error"


# --- the full gate flow -----------------------------------------------------
# --- the full flow -----------------------------------------------------

def test_full_authoring_flow_validates_green(repo):
apply_cli("scaffold", "principle", "--project", "payments", "--id", "data-locality")
Expand Down
12 changes: 6 additions & 6 deletions tests/e2e/test_body_sections_detail.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Phase-20 gate (archived at tag archive/pre-github): richer methods & artifacts — schema + fixtures (D34).
"""Richer methods & artifacts — schema + fixtures.

A type may declare an **advisory** ``body.sections`` and a method step an optional
``detail`` (spec 03 §3/§6). The core validates them structurally, carries them
``detail``. The core validates them structurally, carries them
through materialization, and exposes ``sections`` on the loaded model — while
``scaffold``/``commit`` behaviour is unchanged (sections are guidance, not a gate).
``enterprise-heavy`` pins the enriched ``core-ea@1.1.0``, so adopting it
Expand Down Expand Up @@ -38,7 +38,7 @@ def _bootstrap(repo: Path):


def test_enriched_pack_validates():
"""The enriched fixture pack is structurally valid (spec 03 §9)."""
"""The enriched fixture pack is structurally valid."""
assert pack_mod.validate(pack_mod.load(PACK)) == []


Expand All @@ -52,7 +52,7 @@ def test_body_sections_survive_materialization(repo):


def test_model_exposes_type_sections(repo):
"""The loaded model surfaces sections in declared order (Phase-21/22 will read them)."""
"""The loaded model surfaces sections in declared order."""
_bootstrap(repo)
model = model_mod.load(Repo.discover())
cap = model.definitions.types["capability"]
Expand All @@ -71,7 +71,7 @@ def test_step_detail_survives_materialization(repo):


def test_scaffold_body_still_empty(repo):
"""D34: sections are guidance only — ``scaffold`` still writes a front-matter-only
"""Sections are guidance only — ``scaffold`` still writes a front-matter-only
skeleton with an empty body (no pre-seeded headings)."""
_bootstrap(repo)
apply_cli("project", "create", "payments")
Expand All @@ -84,7 +84,7 @@ def test_scaffold_body_still_empty(repo):


def test_malformed_body_sections_rejected():
"""Structural guards: duplicate / invalid section id (spec 03 §3, D34)."""
"""Structural guards: duplicate / invalid section id."""
dup = pack_mod.load(PACK)
dup["artifact_types"][0]["body"]["sections"].append(
{"id": "statement", "heading": "Dup", "guidance": "x"})
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/test_cli_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Phase-0 gate (archived at tag archive/pre-github): ea version envelope + exit code + reproducibility."""
"""``ea version`` envelope + exit code + reproducibility."""

from __future__ import annotations

Expand All @@ -17,7 +17,7 @@ def test_version_envelope_and_exit():
def test_version_output_is_reproducible():
_, _, raw1 = run_cli("version")
_, _, raw2 = run_cli("version")
assert raw1 == raw2 # byte-identical (NFR-1)
assert raw1 == raw2 # byte-identical (P1)


def test_unsupported_contract_version_is_usage_error():
Expand Down
11 changes: 5 additions & 6 deletions tests/e2e/test_commit_diff.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
"""Phase-29 gate (archived at tag archive/pre-github): reviewable commit delta — `data.diff` on the commit dry-run.
"""Reviewable commit delta — `data.diff` on the commit dry-run.

Because the core performs the write, a re-commit (a new artifact version) was not reviewable: the
dry-run returned the full ``preview`` (the after) but nothing showing *what changed* vs. disk. The
core now emits a deterministic ``data.diff`` (unified diff of the assembled content against the current
file) on the ``commit`` dry-run — beside ``plan`` (which files) and ``preview`` (the after). Refines
spec 07 §4. First core change since Phase 27.
file) on the ``commit`` dry-run — beside ``plan`` (which files) and ``preview`` (the after).

Both halves: the objective checks below, and a recorded re-commit session (the diff shown before the
confirm) captured in ``gates/phase-29.md`` (tag ``archive/pre-github``).
confirm) captured in a recorded session.
"""

from __future__ import annotations
Expand Down Expand Up @@ -99,11 +98,11 @@ def test_both_hosts_teach_data_diff_at_review():
spine = (ROOT / "plugins" / host / ARCH / "SKILL.md").read_text()
assert "data.diff" in authoring and "delta" in authoring.lower()
assert "data.diff" in spine
# Presentation (post-D41 feedback): render it readably & proactively, not on demand.
# Presentation (later feedback): render it readably & proactively, not on demand.
for text in (authoring, spine):
assert "```diff" in text # a fenced diff block → red/green rendering
assert "proactive" in text.lower() or "without being asked" in text.lower()
# authoring.md stays byte-identical across hosts (the D33 single-source invariant)
# authoring.md stays byte-identical across hosts (the single-source invariant)
c = (ROOT / "plugins" / "ea-claude" / ARCH / "reference" / "authoring.md").read_bytes()
a = (ROOT / "plugins" / "ea-antigravity" / ARCH / "reference" / "authoring.md").read_bytes()
assert c == a
20 changes: 10 additions & 10 deletions tests/e2e/test_discovery_verbs.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Phase-17 gate (archived at tag archive/pre-github): preset & pack discovery — the read verbs that let a
surface enumerate the selectable building blocks before choosing one (spec 11 §6).
"""Preset & pack discovery — the read verbs that let a
surface enumerate the selectable building blocks before choosing one.

An agent had no contract-native way to see the adoptable presets / packs: it
shelled to ``ls``/``find`` and parsed internal YAML, and ``manifest adopt
<unknown>`` named only the search path — the D31 "defaults to startup-light" root
<unknown>`` named only the search path — the "defaults to startup-light" root
cause. Four read verbs (``preset list``/``show``, ``pack list``/``show``) plus a
self-describing not-found error that enumerates the valid ids inline close it.
All read-only (``ok``/exit 0), pin-native (``pack@version``), projectable (spec 09).
All read-only (``ok``/exit 0), pin-native (``pack@version``), projectable.
"""

from __future__ import annotations
Expand All @@ -30,7 +30,7 @@ def env_paths(tmp_path, monkeypatch):


def test_preset_list_summarizes_each_choice(env_paths):
"""Per-preset summary → an agent compares + picks in one call (spec 11 §3.1)."""
"""Per-preset summary → an agent compares + picks in one call."""
env, code, _ = run_cli("preset", "list")
assert code == 0 and env["status"] == "ok"
by_id = {p["id"]: p for p in env["data"]["presets"]}
Expand All @@ -54,7 +54,7 @@ def test_preset_show_returns_the_full_resolved_preset(env_paths):


def test_unknown_preset_enumerates_available_ids(env_paths):
"""``preset show <unknown>`` → exit 2 listing the valid ids (spec 11 §4)."""
"""``preset show <unknown>`` → exit 2 listing the valid ids."""
env, code, _ = run_cli("preset", "show", "bogus")
assert code == 2 and env["status"] == "error"
msg = env["diagnostics"][0]["message"]
Expand All @@ -63,7 +63,7 @@ def test_unknown_preset_enumerates_available_ids(env_paths):


def test_manifest_adopt_unknown_enumerates_presets(env_paths):
"""The D31 root-cause command: ``adopt <unknown>`` now teaches the choice.
"""The root-cause command: ``adopt <unknown>`` now teaches the choice.

It routes through the same resolver, so fixing the resolver fixes adopt for
free — proven on the very command that exhibited the gap.
Expand Down Expand Up @@ -104,22 +104,22 @@ def test_unknown_pack_version_enumerates_available(env_paths):


def test_bare_pack_id_requires_an_explicit_version(env_paths):
"""Pin-native (D27): ``pack show core-ea`` enumerates that pack's versions."""
"""Pin-native: ``pack show core-ea`` enumerates that pack's versions."""
env, code, _ = run_cli("pack", "show", "core-ea")
assert code == 2 and env["status"] == "error"
msg = env["diagnostics"][0]["message"]
assert "core-ea@1.0.0" in msg and "core-ea@1.1.0" in msg


def test_discovery_reads_are_byte_stable(env_paths):
"""Identical inputs → byte-identical stdout (NFR-1)."""
"""Identical inputs → byte-identical stdout (P1)."""
_, _, a = run_cli("pack", "list")
_, _, b = run_cli("pack", "list")
assert a == b and a.strip().startswith("{")


def test_discovery_verbs_are_projectable(env_paths):
"""Read verbs carry spec-09 projection: discover then trim (subtractive)."""
"""Read verbs carry projection: discover then trim (subtractive)."""
env, code, _ = run_cli("pack", "show", "core-ea@1.1.0", "--list-fields")
assert code == 0 and "methods" in env["data"]["fields"]

Expand Down
12 changes: 6 additions & 6 deletions tests/e2e/test_drift_guard.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
"""Phase-13 gate (archived at tag archive/pre-github): multi-writer concurrency — resolved by DECISION (D26).
"""Multi-writer concurrency — resolved by DECISION.

Q11 is resolved **without** building a concurrency-control subsystem. The unit of
Concurrency is resolved **without** building a concurrency-control subsystem. The unit of
work is a single writer on a git worktree/branch; **git** mediates reconciliation
*between* writers (branch/merge/rebase, which never silently drop a write); and the
D5 confirmation-token drift guard already enforces single-writer safety *within* one
tree. Phase 13 is therefore rescoped from "implement a concurrency model" to a
confirmation-token drift guard already enforces single-writer safety *within* one
tree. This is therefore rescoped from "implement a concurrency model" to a
one-line protocol hardening — a ``create`` now binds the prior absence of its path,
so a create-create race trips the same drift guard as an update/delete — plus this
gate, which proves the end-to-end property the original phase demanded: **two writers
test, which proves the end-to-end property demanded: **two writers
against the same source of truth never silently lose a write.**

Three cases, one per layer of the model:

1. **intra-tree drift** — a second same-tree writer's stale ``--confirm`` is refused
(exit 4); the existing D5 mechanism *is* single-writer-per-worktree enforcement.
(exit 4); the existing mechanism *is* single-writer-per-worktree enforcement.
2. **create-create** — two writers creating the same artifact: the second is refused
and the first's file is intact (no clobber). The protocol-level backstop for a
caller without a pre-flight check is unit-tested in
Expand Down
14 changes: 7 additions & 7 deletions tests/e2e/test_full_surface_flow.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
"""Phase-8 gate (archived at tag archive/pre-github): the second adapter surface.
"""The second adapter surface.

The Antigravity plugin is a *thin adapter* — it changes no core code (spec 08 §8);
The Antigravity plugin is a *thin adapter* — it changes no core code;
its proof is that the **exact CLI sequence the plugin drives** runs green over the
unchanged contract. That sequence extends the Phase-2 flow (adopt → scaffold/commit
×2) with a final **promotion**, matching the gate's "tailors → authors → promotes":
unchanged contract. That sequence extends the flow (adopt → scaffold/commit
×2) with a final **promotion**, matching "tailors → authors → promotes":

init → manifest adopt startup-light → scaffold/commit principle
→ scaffold/commit capability → promote principle → validate --all

The conversational surface itself (the judgment layer) is proven separately by a
recorded real ``agy`` session under ``gates/phase-8.md`` (tag ``archive/pre-github``) (P5-3); this test pins the
recorded real ``agy`` session (P5-3); this test pins the
contract path that session rides, including the two-phase ``--confirm`` token at every
guarded write and the cross-scope fall-through after promotion.
"""
Expand Down Expand Up @@ -67,7 +67,7 @@ def test_full_surface_flow_authors_promotes_and_validates_green(repo):
"""The whole plugin sequence, end to end, lands green on the unchanged core."""
_author(repo)

# Flow C — promote the principle to Org via a reviewed, confirmed plan (spec 08 §6.5).
# Flow C — promote the principle to Org via a reviewed, confirmed plan.
env, code, _ = apply_cli("promote", "principle", "data-locality", "--project", "payments")
assert code == 0 and env["status"] == "ok"
assert env["data"]["applied"] == {"created": 1, "updated": 0, "deleted": 1}
Expand All @@ -89,7 +89,7 @@ def test_every_guarded_write_is_two_phase(repo):
"""Each guarded write the surface drives plans first (token), refusing a bare apply path.

A dry-run returns a confirmation_token and writes nothing; only the --confirm re-run
applies. This is the one write protocol (spec 07 §8) the second surface reuses verbatim.
applies. This is the one write protocol the second surface reuses verbatim.
"""
# scaffold dry-run: token present, nothing on disk.
plan, code, _ = run_cli("scaffold", "principle", "--project", "payments",
Expand Down
Loading
Loading