diff --git a/crates/engine/src/cmd/draw/ellipse.rs b/crates/engine/src/cmd/draw/ellipse.rs
--- a/crates/engine/src/cmd/draw/ellipse.rs
+++ b/crates/engine/src/cmd/draw/ellipse.rs
@@ -31,19 +31,24 @@ pub(super) struct EllipseM {
     /// The `Parameter` option: arc start/end values are ellipse parameters, not true angles.
     param: bool,
     start: Option<f64>,
+    /// The `Included angle` option: the next value is the arc's angle from its start angle.
+    included: bool,
     /// The Isocircle option (isometric snap style) in progress.
     iso: Option<crate::cmd::settings::iso::IsoCircle>,
 }
 
 impl EllipseM {
     fn axis(&self) -> Option<(Vec2, Vec2)> {
-        // (center, major vector)
+        // (center, major vector): towards the first axis endpoint, as AutoCAD stores it.
         match (self.center_mode, self.pts.as_slice()) {
             (true, [c, e, ..]) => Some((*c, *e - *c)),
-            (false, [a, b, ..]) => Some((a.mid(*b), *b - a.mid(*b))),
+            (false, [a, b, ..]) => Some((a.mid(*b), *a - a.mid(*b))),
             _ => None,
         }
     }
+    /// The other half axis reaches as far as `other` is from the center (AutoCAD measures the
+    /// picked point's distance from the center, not from the first axis). Longer than the
+    /// first half axis, it becomes the major axis: the first axis turned 90° counterclockwise.
     fn build(&self, other: Vec2) -> Option<Ellipse> {
         let (c, m) = self.axis()?;
         let ml = m.len();
@@ -51,7 +56,7 @@ impl EllipseM {
             return None;
         }
         let u = m / ml;
-        let minor = ((other - c).dot(u.perp())).abs();
+        let minor = (other - c).len();
         let (major, ratio) = if minor > ml { (u.perp() * minor, ml / minor) } else { (m, minor / ml) };
         (ratio > 1e-9).then_some(Ellipse::full(c, major, ratio.min(1.0)))
     }
@@ -85,13 +90,16 @@ impl Interactive for EllipseM {
     }
     fn prompt(&self, s: &Session) -> Prompt {
         if let Some(e) = &self.ellipse {
-            let msg = match (self.start.is_none(), self.param) {
-                (true, false) => "Specify start angle",
-                (false, false) => "Specify end angle",
-                (true, true) => "Specify start parameter",
-                (false, true) => "Specify end parameter",
+            if self.included {
+                return Prompt::new("Specify included angle for arc", Accept::POINT_OR_NUMBER).default("180").base(e.center);
+            }
+            let (msg, kw): (&str, &[&str]) = match (self.start.is_none(), self.param) {
+                (true, false) => ("Specify start angle", &["Parameter"]),
+                (false, false) => ("Specify end angle", &["Parameter", "Included angle"]),
+                (true, true) => ("Specify start parameter", &["Angle"]),
+                (false, true) => ("Specify end parameter", &["Angle"]),
             };
-            return Prompt::new(msg, Accept::POINT_OR_NUMBER).kw(if self.param { &["Angle"] } else { &["Parameter"] }).base(e.center);
+            return Prompt::new(msg, Accept::POINT_OR_NUMBER).kw(kw).base(e.center);
         }
         if let Some(iso) = &self.iso {
             return iso.prompt();
@@ -109,11 +117,32 @@ impl Interactive for EllipseM {
     fn input(&mut self, s: &mut Session, i: Input) -> Result<Step> {
         if let Some(e) = self.ellipse {
             let ge = Ellipse { start: 0.0, end: cadcraft_geom::TAU, ..e };
+            if self.included {
+                let incl = match i {
+                    Input::Point(p) => (p - e.center).angle(),
+                    Input::Text(t) => s.angle_settings().amount(&t).ok_or_else(|| crate::EngineError::Other("Requires an angle.".into()))?,
+                    Input::Enter => std::f64::consts::PI,
+                    _ => return Ok(Step::Continue),
+                };
+                // A true angle added to the start angle (AutoCAD: start 214.659°, included
+                // 232.716° ends the arc at 87.375° from the major axis).
+                let st = self.start.unwrap_or(0.0);
+                let end = ge.param_of(e.center + Vec2::from_angle((ge.at_param(st) - e.center).angle() + incl));
+                s.add_entity(EntityKind::Ellipse(cadcraft_doc::Ellipse {
+                    center: v3(e.center),
+                    major: v3(e.major),
+                    ratio: e.ratio,
+                    start: st,
+                    end,
+                }))?;
+                return Ok(Step::Done);
+            }
             let ang = match i {
                 Input::Keyword(k) => {
                     match k.as_str() {
                         "Parameter" => self.param = true,
                         "Angle" => self.param = false,
+                        "Included angle" if self.start.is_some() && !self.param => self.included = true,
                         _ => {}
                     }
                     return Ok(Step::Continue);
diff --git a/crates/engine/src/cmd/draw2.rs b/crates/engine/src/cmd/draw2.rs
--- a/crates/engine/src/cmd/draw2.rs
+++ b/crates/engine/src/cmd/draw2.rs
@@ -105,7 +105,7 @@ pub fn specs() -> Vec<CommandSpec> {
             .interactive(|_| Ok(Box::new(TanCircleM::new(false)))),
         CommandSpec::new("ellipse.axis", "Axis, End", run_ellipse_axis)
             .menu(&["Draw", "Ellipse", "Axis, End"])
-            .params("{p1, p2, distance} | {p1, p2, p3} (axis endpoints, then half the other axis)")
+            .params("{p1, p2, distance} | {p1, p2, p3} (axis endpoints, then half the other axis: a distance, or a point that far from the center)")
             .interactive(|_| Ok(super::draw::ellipse_machine(false, false))),
         CommandSpec::new("ellipse.arc", "Elliptical Arc", run_ellipse_arc)
             .menu(&["Draw", "Ellipse", "Arc"])
diff --git a/crates/engine/src/cmd/draw2/ellipse.rs b/crates/engine/src/cmd/draw2/ellipse.rs
--- a/crates/engine/src/cmd/draw2/ellipse.rs
+++ b/crates/engine/src/cmd/draw2/ellipse.rs
@@ -4,7 +4,8 @@ use super::*;
 
 fn ellipse_from_axis(p1: Vec2, p2: Vec2, half: f64) -> Option<Ellipse> {
     let c = p1.mid(p2);
-    let m = p2 - c;
+    // The major axis points at the first endpoint, as AutoCAD stores it.
+    let m = p1 - c;
     let ml = m.len();
     let half = half.abs();
     if ml < 1e-12 || half < 1e-12 || !half.is_finite() {
@@ -17,10 +18,8 @@ fn axis_ellipse_params(cmd: &str, p: &Value) -> Result<Ellipse> {
     let p1 = point_req(cmd, p, "p1")?;
     let p2 = point_req(cmd, p, "p2")?;
     let half = match point_param(p, "p3") {
-        Some(p3) => {
-            let ax = Line::new(p1, p2);
-            ax.project(p3).dist(p3)
-        }
+        // As at the prompt: the point's distance from the center, not from the first axis.
+        Some(p3) => p3.dist(p1.mid(p2)),
         None => f64_req(cmd, p, "distance")?,
     };
     ellipse_from_axis(p1, p2, half).ok_or_else(|| bad(cmd, "degenerate ellipse"))
diff --git a/crates/engine/src/cmd/draw2/tests.rs b/crates/engine/src/cmd/draw2/tests.rs
--- a/crates/engine/src/cmd/draw2/tests.rs
+++ b/crates/engine/src/cmd/draw2/tests.rs
@@ -270,6 +270,118 @@ fn ellipse_arc_typed_angles_are_true_angles() {
     }
 }
 
+/// Typed ELLIPSE input against what AutoCAD 2024 stores for the same input (black-box: synthetic
+/// input in accoreconsole, read back with `entget`). The major axis points at the first axis
+/// endpoint; a point at the distance prompt gives its distance from the center; an other axis
+/// longer than the first becomes the major axis, the first turned 90° counterclockwise; the
+/// Included angle is added to the start angle.
+#[test]
+fn ellipse_axis_endpoints_match_autocad() {
+    type Case = (&'static str, [f64; 2], [f64; 2], f64, Option<[f64; 2]>);
+    // (input after ELLIPSE, center, major axis, ratio, arc start/end parameters)
+    let cases: [Case; 10] = [
+        // The other axis (27.02) is longer than the first half axis (26.42).
+        (
+            "16.459468652708743,28.120073391143574 -5.034438825478263,-20.14843889196848 27.021868057769268",
+            [5.712514913615239, 3.985817249587547],
+            [-24.6850622596004, 10.99222700689644],
+            0.9776866627982613,
+            None,
+        ),
+        (
+            "33.45015752893423,-27.997665254733153 1.0902141405158297,-9.876490849047837 _R 36.361957504949",
+            [17.27018583472502, -18.93707805189049],
+            [16.1799716942092, -9.060587202842658],
+            0.8052876303433125,
+            None,
+        ),
+        (
+            "0.5161247992610992,0.27380397971284964 0.49874786589184156,0.23294359917255586 0.0026647279687818256",
+            [0.5074363325764704, 0.2533737894427027],
+            [0.00868846668462886, 0.02043019027014691],
+            0.1200276615332929,
+            None,
+        ),
+        // Arcs: the angles are taken from the major axis, so a reversed axis draws the arc
+        // on the opposite side of the center.
+        (
+            "_A 612354.66928411,2398796.595432055 612364.9910379789,2398751.70959102 3.5361631006792016 259.40675054209663 162.0895061623204",
+            [612359.8301610444, 2398774.152511537],
+            [-5.160876934416592, 22.44292051764205],
+            0.1535548572193783,
+            Some([4.683678586016272, 2.014340486820176]),
+        ),
+        (
+            "_A -32.49789607178266,25.826299666765127 16.360636510348964,-6.670894598441254 9.326202777586586 _P 235.35128996877393 341.0349294763654",
+            [-8.068629780716847, 9.577702534161936],
+            [-24.42926629106581, 16.24859713260318],
+            0.317871961092373,
+            Some([4.107654908771007, 5.952182383669234]),
+        ),
+        (
+            "_A _C 15.895131938563559,-16.135236520373613 1.9672122380661037,-18.61293795336168 14.456880177932417 214.65903577683966 _I 232.7163597705933",
+            [15.89513193856356, -16.13523652037361],
+            [2.53204749973717, -14.23341561039267],
+            0.9785367111972643,
+            Some([3.756694588158375, 1.5259701966906878]),
+        ),
+        (
+            "_A _C 1.8822645373261935,-7.920292708078534 28.89115893105938,-23.280023918605742 38.7551404612689 136.20071263173944 _I 129.90755425686075",
+            [1.882264537326193, -7.920292708078534],
+            [19.15838502833398, 33.68853210335513],
+            0.8017236937148501,
+            Some([2.267136066480607, 4.657903136501946]),
+        ),
+        // The other axis given by a point.
+        (
+            "-16.377480557612035,55.44699770062272 -15.579405511585826,-24.406726331471475 -4.27081078679767,42.69814401696656",
+            [-15.97844303459893, 15.52013568457562],
+            [-0.3990375230131046, 39.92686201604709],
+            0.7411292927991227,
+            None,
+        ),
+        (
+            "8.137326847228081,16.045209411091605 -2.4500932561568627,22.585405165312338 -2.4956573993017335,12.374292543621266",
+            [2.843616795535609, 19.31530728820197],
+            [4.602217644463162, 7.450176331143755],
+            0.7105482899194384,
+            None,
+        ),
+        (
+            "_C 15.418189586495892,-18.741133769301225 43.29367724019212,5.337090633133826 12.043993630141971,-7.0535727363182446",
+            [15.41818958649589, -18.74113376930122],
+            [27.87548765369622, 24.07822440243505],
+            0.3302549104883693,
+            None,
+        ),
+    ];
+    use std::f64::consts::{PI, TAU};
+    let same = |a: f64, b: f64| (a - b).abs() <= 1e-9 * a.abs().max(b.abs()).max(1.0);
+    let same_angle = |a: f64, b: f64| {
+        let d = (a - b).rem_euclid(TAU);
+        d < 1e-9 || TAU - d < 1e-9
+    };
+    for (input, center, major, ratio, arc) in cases {
+        let mut s = Session::new();
+        s.cmdline(&format!("ellipse {input}")).unwrap();
+        assert!(s.running.is_none(), "{input}: {}", s.prompt_text());
+        let EntityKind::Ellipse(e) = last(&s) else { panic!("{input}: no ellipse") };
+        assert!(same(e.center.x, center[0]) && same(e.center.y, center[1]), "{input}: center {:?}", e.center);
+        assert!(same(e.major.x, major[0]) && same(e.major.y, major[1]), "{input}: major {:?}", e.major);
+        assert!(same(e.ratio, ratio), "{input}: ratio {}", e.ratio);
+        let [start, end] = arc.unwrap_or([0.0, TAU]);
+        assert!(same_angle(e.start, start) && same_angle(e.end, end), "{input}: {} {}", e.start, e.end);
+    }
+    // Enter takes the default included angle, 180°: half the ellipse.
+    let mut s = Session::new();
+    s.cmdline("ellipse _A 10,0 -10,0 5 30 _I").unwrap();
+    assert!(s.prompt_text().contains("included angle"), "{}", s.prompt_text());
+    s.input(Input::Enter).unwrap();
+    assert!(s.running.is_none(), "{}", s.prompt_text());
+    let EntityKind::Ellipse(e) = last(&s) else { panic!("no ellipse") };
+    assert!(same_angle(e.end, e.start + PI), "{} {}", e.start, e.end);
+}
+
 // ---------------- DIVIDE / MEASURE ----------------
 
 #[test]
diff --git a/docs/geometry-parity.md b/docs/geometry-parity.md
--- a/docs/geometry-parity.md
+++ b/docs/geometry-parity.md
@@ -1,6 +1,6 @@
 # Geometry parity
 
-> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-22 · **Change:** minor (bounded constraint expression and parameter depth) · **Target:** Autodesk AutoCAD 2027
+> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-26 · **Change:** minor (ELLIPSE axis endpoints, other-axis point and Included angle as AutoCAD stores them) · **Target:** Autodesk AutoCAD 2027
 
 CAD users trust numbers: a trimmed endpoint, an offset, an intersection or an area is either right
 to the last displayed digit or the tool is unusable for production drawings. This document
@@ -18,10 +18,13 @@ drawings behave differently from mid-sized ones. 3D geometry doesn't exist. Rema
 
 ## How this was measured
 
-Read from the source on 2026-10-10 (main at bd2412f), with file:line evidence in the tables. No
-numeric comparison against AutoCAD has been run yet: the plan is a set of synthetic drawings whose
-exact answers are known analytically, measured in both apps black-box (LIST, ID, AREA results)
-and in CADCraft headless. Until then the percentages are judgements.
+Read from the source on 2026-10-10 (main at bd2412f), with file:line evidence in the tables. The
+one numeric comparison against AutoCAD so far is ELLIPSE from axis endpoints (2026-10-26): 11
+typed inputs measured black-box in AutoCAD 2024 (accoreconsole, read back with `entget`) and
+pinned by `ellipse_axis_endpoints_match_autocad`. Everything else is still to be measured: the
+plan is a set of synthetic drawings whose exact answers are known analytically, measured in both
+apps black-box (LIST, ID, AREA results) and in CADCraft headless. Until then the percentages are
+judgements.
 
 Weights (how much AutoCAD users lean on each area in 2D drafting): numeric robustness 15%,
 curve representation 10%, intersections 15%, offsets 15%, trim/extend/fillet/chamfer/break/join
@@ -157,6 +160,7 @@ Total ≈ 90–140 h; items 1–6 parallelise across two or three agents.
 
 | Date | Change | Summary |
 |---|---|---|
+| 2026-10-26 | minor | ELLIPSE from axis endpoints matches AutoCAD's stored geometry: the major axis points at the first endpoint (arcs drew on the opposite side of the center), a point at the other-axis prompt gives its distance from the center, and the end-angle prompt offers Included angle |
 | 2026-10-22 | minor | Constraint expressions count operator chains toward the syntax-tree depth limit; evaluation shares one depth limit across operators and parameter references, with a 1 MiB-stack regression (#1936) |
 | 2026-10-14 | trivial | JOIN Close: a single arc becomes its circle, a single elliptical arc its full ellipse (#1175) |
 | 2026-10-12 | trivial | TRIM on a closed polyline keeps only the complementary run when the pick lies past the last cut (#726) |
