stata-code 0.9.0__tar.gz → 0.9.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {stata_code-0.9.0 → stata_code-0.9.1}/.gitignore +2 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/CHANGELOG.md +151 -7
- {stata_code-0.9.0 → stata_code-0.9.1}/PKG-INFO +9 -2
- {stata_code-0.9.0 → stata_code-0.9.1}/PUBLISHING.md +16 -7
- {stata_code-0.9.0 → stata_code-0.9.1}/README.md +8 -1
- {stata_code-0.9.0 → stata_code-0.9.1}/SCHEMA.md +3 -1
- {stata_code-0.9.0 → stata_code-0.9.1}/docs/competitive-landscape.md +2 -2
- {stata_code-0.9.0 → stata_code-0.9.1}/pyproject.toml +1 -1
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/__init__.py +1 -1
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/_pool.py +328 -89
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/_runtime.py +13 -2
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/log_artifacts.py +3 -1
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/runner.py +44 -6
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/kernel/kernel.py +6 -3
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/mcp/server.py +5 -2
- stata_code-0.9.1/tests/test_bugfix_regressions.py +556 -0
- stata_code-0.9.1/tests/test_mcp_kernel_extra.py +1087 -0
- stata_code-0.9.1/tests/test_pool_refs_extra.py +993 -0
- stata_code-0.9.1/tests/test_runner_helpers.py +1121 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/LICENSE +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/LICENSE-POLICY.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/docs/design/hard_timeout.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/docs/industry-leader-roadmap.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/examples/01-basic-regression.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/examples/02-did-card-krueger.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/examples/03-graphs.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/examples/04-multi-session.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/examples/05-large-matrix.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/examples/06-cross-stack-parity-audit.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/examples/07-data-mcp-handoff.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/examples/README.md +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/schema/run_result.schema.json +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/scripts/build_skill_zip.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/scripts/check_github_actions.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/scripts/check_versions.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/scripts/export_schema.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/__main__.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/cli.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/__init__.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/_refs.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/errors.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/estimation.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/handoff.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/notebook.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/provenance.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/run_index.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/core/schema.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/doctor.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/kernel/__init__.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/kernel/__main__.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/kernel/assets/logo-32x32.png +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/kernel/assets/logo-64x64.png +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/kernel/assets/logo-svg.svg +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/mcp/__init__.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/stata_code/mcp/__main__.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/__init__.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/conftest.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/fixtures/.gitkeep +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_cancel.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_doctor.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_errors.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_estimation.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_github_actions.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_handoff.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_kernel.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_log_artifacts.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_mcp.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_mcp_stdio.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_method_prompts.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_new_tools.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_notebook.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_notebook_phase2.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_pool.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_provenance.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_public_api.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_real_stata.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_release_versions.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_run_index.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_runner.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_runtime_discovery.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_schema.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_schema_artifact.py +0 -0
- {stata_code-0.9.0 → stata_code-0.9.1}/tests/test_skill_package.py +0 -0
|
@@ -4,6 +4,152 @@ All notable changes to `stata-code` are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the project adheres
|
|
5
5
|
to semver-major.minor for the result schema (see `SCHEMA.md` §6).
|
|
6
6
|
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## 0.9.1 — 2026-07-22
|
|
10
|
+
|
|
11
|
+
Quality-hardening pass: correctness fixes from an adversarial code review,
|
|
12
|
+
a large offline test expansion, and a documentation accuracy audit. No new
|
|
13
|
+
features, no API or schema changes.
|
|
14
|
+
|
|
15
|
+
A second review round found that three of the first round's fixes were
|
|
16
|
+
incomplete or had introduced a regression of their own; those are the first
|
|
17
|
+
four entries below. The common failure was testing a fix in isolation while
|
|
18
|
+
the real call path stayed uncovered — the new tests go through `SessionPool`
|
|
19
|
+
rather than `WorkerProcess` wherever the pool is what carries the bug, and
|
|
20
|
+
each was confirmed to fail against the pre-fix source.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **A read-only status query no longer kills a healthy mid-run worker.**
|
|
25
|
+
Once `send_simple_op` learned to bail out rather than block on the worker
|
|
26
|
+
lock, that bail-out surfaced as a `_WorkerTimeout` — and
|
|
27
|
+
`SessionPool.stata_info` treated "busy" and "dead" identically: it
|
|
28
|
+
SIGTERMed the worker and dropped it from the pool. Calling the
|
|
29
|
+
`stata_info` tool during a long `bootstrap`/`reghdfe` therefore returned
|
|
30
|
+
the user's run as `adapter_crash` and wiped the session's loaded data, and
|
|
31
|
+
because the MCP layer swallows the exception the kill was invisible in the
|
|
32
|
+
tool response. Busy is now a distinct `_WorkerBusy` signal (a
|
|
33
|
+
`_WorkerTimeout` subclass, so warn-only callers are unaffected) that never
|
|
34
|
+
kills.
|
|
35
|
+
- **A timed-out read no longer steals the next request's response.** Each
|
|
36
|
+
request spawned its own `readline()` thread and abandoned it on deadline
|
|
37
|
+
overrun; the orphan stayed blocked on the pipe and consumed the *following*
|
|
38
|
+
response. The next `execute()` then burned its entire timeout (default
|
|
39
|
+
600 s) waiting for a reply that had already been eaten, after which the
|
|
40
|
+
pool killed a perfectly healthy worker. Reads now come off one long-lived
|
|
41
|
+
pump thread per worker, which cannot orphan, and responses carrying a
|
|
42
|
+
stale request id are discarded rather than mis-matched.
|
|
43
|
+
- **`send_simple_op` honors its full timeout budget.** The read deadline was
|
|
44
|
+
computed *after* acquiring the worker lock, so a call that spent most of
|
|
45
|
+
its budget waiting for the lock got a second full budget for the read —
|
|
46
|
+
worst case 2x `timeout_ms`, and `list_session_info_detailed` iterates
|
|
47
|
+
workers serially, so N busy workers stalled the status tool for
|
|
48
|
+
`2 * timeout * N`. The deadline is now fixed up front.
|
|
49
|
+
- **Repeated identical notes are no longer double-counted.** The previous
|
|
50
|
+
de-dup short-circuited before recording the matched span, so the second and
|
|
51
|
+
later copies of an identical `note:` line went unclaimed and were picked up
|
|
52
|
+
again by the generic-note pass — the exact double-count the fix was meant
|
|
53
|
+
to remove, reachable from any `foreach` loop re-running the same
|
|
54
|
+
regression.
|
|
55
|
+
- **`stata_info`'s worker eviction is identity-checked.** It popped the
|
|
56
|
+
session's worker unconditionally, so a concurrent `execute()` that had
|
|
57
|
+
already noticed the death and registered a replacement got *its* worker
|
|
58
|
+
evicted — leaking a live pystata subprocess that `request_cancel` /
|
|
59
|
+
`kill_session` / `shutdown` could no longer reach.
|
|
60
|
+
- **`kill()`'s already-dead fast path is identity-checked** too, matching its
|
|
61
|
+
own slow path: it could otherwise clear a handle a concurrent `execute()`
|
|
62
|
+
had just respawned into, stranding a live subprocess mid-request.
|
|
63
|
+
- **`TypeError` is no longer blanket-classified as a caller error.** The
|
|
64
|
+
guard wrapped the whole `execute()` call, not just argument binding, so a
|
|
65
|
+
`TypeError` raised deep inside result collection told the agent its
|
|
66
|
+
arguments were wrong when nothing was — and routed the failure out of the
|
|
67
|
+
`adapter_crash` path that would have recycled the wedged worker. Malformed
|
|
68
|
+
options are now caught by signature binding before the call; deeper
|
|
69
|
+
`TypeError`s stay in the `worker_error` bucket.
|
|
70
|
+
- **Session ids longer than Stata's 32-character name cap are mapped.** They
|
|
71
|
+
were passed through verbatim as a frame name, so `frame create` failed with
|
|
72
|
+
rc 198; they now route through the hashed mapped-frame path.
|
|
73
|
+
|
|
74
|
+
- **Worker stderr pipe is now drained continuously.** The subprocess pool
|
|
75
|
+
only read a worker's stderr after death, so a worker whose cumulative
|
|
76
|
+
stderr output (pystata banners, Stata C-side messages, warnings) exceeded
|
|
77
|
+
the ~64 KB OS pipe buffer blocked mid-write and never responded — the
|
|
78
|
+
parent then misreported the healthy worker as a `timeout` and killed it
|
|
79
|
+
(or hung forever with `timeout_ms=None`). A per-worker daemon thread now
|
|
80
|
+
drains stderr into a bounded tail buffer, which also enriches crash
|
|
81
|
+
messages.
|
|
82
|
+
- **A worker-reported failure no longer destroys the session.** A live
|
|
83
|
+
worker answering `{ok:false, error_kind:"worker_error"}` was handled like
|
|
84
|
+
a dead process: killed and dropped from the pool, wiping the session's
|
|
85
|
+
loaded dataset and `r()`/`e()` state — reachable from a mere argument
|
|
86
|
+
type typo. Such failures now surface as structured errors while the
|
|
87
|
+
worker (and the session's data) survives; the worker also classifies
|
|
88
|
+
`TypeError` as `invalid_request`.
|
|
89
|
+
- **LRU eviction skips busy workers.** `last_used` is stale for a mid-run
|
|
90
|
+
worker, so capacity pressure from an unrelated new session preferred the
|
|
91
|
+
longest-running request as its eviction victim (SIGTERM mid-run →
|
|
92
|
+
`adapter_crash`, session data lost). Eviction now skips in-flight
|
|
93
|
+
workers, bumps `last_used` at request start, and kills victims outside
|
|
94
|
+
the pool lock; timeout/error cleanup no longer removes a newer worker
|
|
95
|
+
handle registered in the interim.
|
|
96
|
+
- **Status queries no longer hang behind a long run.** `send_simple_op`
|
|
97
|
+
blocked unboundedly on the worker lock held by an in-flight `execute()`;
|
|
98
|
+
lock acquisition now counts against the same timeout budget and surfaces
|
|
99
|
+
as a per-session "busy" warning.
|
|
100
|
+
- **`rc` is taken from the last `r(NNN);` in a failure transcript.** An
|
|
101
|
+
earlier successful command echoing a literal `r(NNN);` (display string,
|
|
102
|
+
help output) previously hijacked the return code — and therefore the
|
|
103
|
+
`ErrorKind` classification, suggestions, and recovery contract.
|
|
104
|
+
- **Indented notes are no longer double-counted as warnings.** An indented
|
|
105
|
+
`note: … omitted because of collinearity` line produced both an
|
|
106
|
+
`omitted_collinear` and a generic `note` warning.
|
|
107
|
+
- **A session literally named `"default"` no longer aliases `"main"`.** In
|
|
108
|
+
in-process mode it silently shared `main`'s Stata frame (one dataset for
|
|
109
|
+
two nominally distinct sessions); it now routes through the private
|
|
110
|
+
mapped-frame path.
|
|
111
|
+
- **Matrices with missing sfi row/col names are no longer dropped.**
|
|
112
|
+
Positional names (`r1…`/`c1…`) are synthesized instead of letting the
|
|
113
|
+
shape validator silently discard successfully read values.
|
|
114
|
+
- **`get_graph(format=…)` is no longer a silent no-op.** Requesting a
|
|
115
|
+
format different from the stored one now returns `invalid_request`
|
|
116
|
+
instead of returning mismatched bytes.
|
|
117
|
+
- **Post-run file snapshots survive escaping symlinks.** A symlink inside
|
|
118
|
+
the working dir pointing outside it crashed `changed_output_files` with
|
|
119
|
+
an uncaught `ValueError`; it is now skipped.
|
|
120
|
+
|
|
121
|
+
### Added
|
|
122
|
+
|
|
123
|
+
- **≈300 new offline tests** (467 → 724 passing without Stata); coverage
|
|
124
|
+
73% → 90% overall (`mcp/server` 74→99%, `kernel` 73→98%, `_pool` 68→96%,
|
|
125
|
+
`_refs` 68→100%, `log_artifacts` 76→96%, `runner` 29→72%). The package is
|
|
126
|
+
now fully mypy-clean, including the previously unchecked top-level
|
|
127
|
+
modules.
|
|
128
|
+
- **Community health files**: `CONTRIBUTING.md` (dev setup + the exact CI
|
|
129
|
+
gates), `CODE_OF_CONDUCT.md` (Contributor Covenant 2.1), `SECURITY.md`,
|
|
130
|
+
and GitHub issue templates that ask for `stata-code doctor` output.
|
|
131
|
+
- **Second-round regression tests** for the eight fixes listed above, each
|
|
132
|
+
verified to fail against the pre-fix source (823 passing locally with
|
|
133
|
+
Stata). They drive real subprocess workers through `SessionPool` — a
|
|
134
|
+
status query racing a live run, a worker that drops its first request, a
|
|
135
|
+
worker that releases the lock partway — rather than asserting on a mocked
|
|
136
|
+
seam, which is what let the first round's regressions through.
|
|
137
|
+
|
|
138
|
+
### Docs
|
|
139
|
+
|
|
140
|
+
- Regenerated the skill's `rc → kind` reference from `errors.py` — it still
|
|
141
|
+
documented the pre-0.9.0 mappings the taxonomy audit had corrected; fixed
|
|
142
|
+
the "32 kinds" claims (the enum has 31).
|
|
143
|
+
- `plugin.json` install verify no longer uses `stata-code-mcp --help`
|
|
144
|
+
(which hangs); it runs `stata-code doctor --no-stata-probe`.
|
|
145
|
+
- PUBLISHING.md / AGENTS.md version-bump lists now cover all eight version
|
|
146
|
+
literals the release gate checks; removed the stale claim that a built
|
|
147
|
+
`.vsix` ships in the repo.
|
|
148
|
+
- SCHEMA.md documents `EstimationResult.command_family` and `.diagnostics`;
|
|
149
|
+
status lines updated v0.8 → v0.9; README.zh.md re-synced with the English
|
|
150
|
+
README (plugin-marketplace install, per-client MCP config table, Open VSX
|
|
151
|
+
and first-activation notes, cell/section conventions).
|
|
152
|
+
|
|
7
153
|
## 0.9.0 — 2026-06-23
|
|
8
154
|
|
|
9
155
|
### Fixed
|
|
@@ -226,8 +372,8 @@ to semver-major.minor for the result schema (see `SCHEMA.md` §6).
|
|
|
226
372
|
|
|
227
373
|
### Added
|
|
228
374
|
|
|
229
|
-
- **Claude Code plugin marketplace manifest.** `.claude-plugin/marketplace.json`
|
|
230
|
-
|
|
375
|
+
- **Claude Code plugin marketplace manifest.** `.claude-plugin/marketplace.json` +
|
|
376
|
+
`.claude-plugin/plugin.json` expose the repo as a single-plugin
|
|
231
377
|
marketplace, so users can install everything (MCP server config + agent
|
|
232
378
|
skill) with `claude plugin marketplace add brycewang-stanford/stata-code`
|
|
233
379
|
followed by `claude plugin install stata-code`.
|
|
@@ -668,6 +814,9 @@ Aggregated from the prior `Unreleased` section; covers 0.6.1 and 0.6.2.
|
|
|
668
814
|
`vscode/package.json`, and the VSCode MCP-client handshake all
|
|
669
815
|
declare `0.3.0`.
|
|
670
816
|
|
|
817
|
+
- **MCP server tool count is now 8** (added `get_matrix`,
|
|
818
|
+
`cancel_session`).
|
|
819
|
+
|
|
671
820
|
### Added
|
|
672
821
|
|
|
673
822
|
- **VSCode extension v0.3 — full UI surface** (`vscode/`). Beyond the
|
|
@@ -750,11 +899,6 @@ Aggregated from the prior `Unreleased` section; covers 0.6.1 and 0.6.2.
|
|
|
750
899
|
in-process and has no clean cancel primitive). Hard interruption
|
|
751
900
|
remains deferred to the subprocess-based runtime planned for v0.3+.
|
|
752
901
|
|
|
753
|
-
### Changed
|
|
754
|
-
|
|
755
|
-
- **MCP server tool count is now 8** (added `get_matrix`,
|
|
756
|
-
`cancel_session`).
|
|
757
|
-
|
|
758
902
|
## [0.2.0] — 2026-05-07
|
|
759
903
|
|
|
760
904
|
The first release that actually ships an end-to-end Stata pipeline. The v1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stata-code
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Summary: Agent-native Stata bridge — one core, multiple frontends (MCP, Jupyter, VSCode)
|
|
5
5
|
Project-URL: Homepage, https://github.com/brycewang-stanford/stata-code
|
|
6
6
|
Project-URL: Repository, https://github.com/brycewang-stanford/stata-code
|
|
@@ -118,7 +118,7 @@ Then just ask:
|
|
|
118
118
|
└─────────────┘ └────────────┘ └─────────────────┘
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
**Status: v0.
|
|
121
|
+
**Status: v0.9 (June 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP. The test suite covers schema, runner, MCP, kernel, notebook, run-index, subprocess-pool, and VS Code modules; CI also checks linting, type safety, schema generation, package metadata, and VSIX packaging. License: **MIT**.
|
|
122
122
|
|
|
123
123
|
Three workflows the current tree explicitly supports for end users and agents:
|
|
124
124
|
|
|
@@ -565,10 +565,17 @@ The `stata_required` marker tags the real-Stata integration tests. CI uses `pyte
|
|
|
565
565
|
|
|
566
566
|
## Contributing
|
|
567
567
|
|
|
568
|
+
Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for the
|
|
569
|
+
development setup, the checks CI runs, and PR guidelines. In short:
|
|
570
|
+
|
|
568
571
|
- Read [LICENSE-POLICY.md](LICENSE-POLICY.md) before opening a PR.
|
|
569
572
|
- Add a one-line acknowledgement to your first PR description; the template is in the policy file.
|
|
570
573
|
- Tests are required for any new schema field or runner behavior.
|
|
571
574
|
|
|
575
|
+
Bug reports and support questions go through
|
|
576
|
+
[GitHub issues](https://github.com/brycewang-stanford/stata-code/issues);
|
|
577
|
+
security reports go through [SECURITY.md](SECURITY.md).
|
|
578
|
+
|
|
572
579
|
---
|
|
573
580
|
|
|
574
581
|
## License
|
|
@@ -20,12 +20,12 @@ Trusted Publishing has two modes:
|
|
|
20
20
|
- **Pending publisher** (preferred for the first release of a brand-new
|
|
21
21
|
project): you configure the trusted publisher *before* the project exists
|
|
22
22
|
on PyPI, and the first successful publish creates it. Go to
|
|
23
|
-
https://pypi.org/manage/account/publishing
|
|
23
|
+
<https://pypi.org/manage/account/publishing/> and add a "pending publisher"
|
|
24
24
|
with the values listed in step 2.
|
|
25
25
|
- **Existing project**: if you already pushed an initial release manually
|
|
26
26
|
(e.g. via `twine upload` with a one-off API token), configure trusted
|
|
27
27
|
publishing on the project page at
|
|
28
|
-
https://pypi.org/manage/project/stata-code/settings/publishing
|
|
28
|
+
<https://pypi.org/manage/project/stata-code/settings/publishing/>.
|
|
29
29
|
|
|
30
30
|
Either path lands you in the same place after the first run.
|
|
31
31
|
|
|
@@ -76,30 +76,39 @@ The environment doesn't need any secrets — Trusted Publishing handles auth.
|
|
|
76
76
|
|
|
77
77
|
Once the one-time setup above is done, every release is just:
|
|
78
78
|
|
|
79
|
-
1. **Bump the version everywhere
|
|
79
|
+
1. **Bump the version everywhere** (eight literals across six files —
|
|
80
|
+
`scripts/check_versions.py` gates the release build on all of them):
|
|
80
81
|
- `pyproject.toml` → `[project] version`
|
|
81
82
|
- `stata_code/__init__.py` → `__version__`
|
|
82
83
|
- `stata_code/mcp/server.py` → `__version__`
|
|
83
84
|
- `vscode/package.json` → `version`
|
|
84
|
-
- `vscode/package-lock.json` →
|
|
85
|
+
- `vscode/package-lock.json` → top-level `version` **and** `packages[""].version`
|
|
86
|
+
- `.claude-plugin/plugin.json` → `version`
|
|
87
|
+
- `.claude-plugin/marketplace.json` → `metadata.version` **and** each `plugins[*].version`
|
|
85
88
|
2. **Run the version guard** before tagging:
|
|
89
|
+
|
|
86
90
|
```bash
|
|
87
91
|
python scripts/check_versions.py
|
|
88
92
|
```
|
|
93
|
+
|
|
89
94
|
3. **Update `CHANGELOG.md`**: move the `[Unreleased]` entries under a new
|
|
90
95
|
`## [X.Y.Z] - YYYY-MM-DD` heading, leaving an empty `[Unreleased]` shell
|
|
91
96
|
on top.
|
|
92
97
|
4. **Commit** the bump:
|
|
98
|
+
|
|
93
99
|
```bash
|
|
94
100
|
git add pyproject.toml stata_code/__init__.py stata_code/mcp/server.py vscode/package.json vscode/package-lock.json CHANGELOG.md
|
|
95
101
|
git commit -m "release: vX.Y.Z"
|
|
96
102
|
```
|
|
103
|
+
|
|
97
104
|
5. **Tag and push**:
|
|
105
|
+
|
|
98
106
|
```bash
|
|
99
107
|
git tag vX.Y.Z
|
|
100
108
|
git push origin main
|
|
101
109
|
git push origin vX.Y.Z
|
|
102
110
|
```
|
|
111
|
+
|
|
103
112
|
6. Watch the **`release` workflow** under the Actions tab. It will:
|
|
104
113
|
- build the sdist + wheel
|
|
105
114
|
- run `twine check` on the artifacts
|
|
@@ -127,14 +136,14 @@ version if a publish has already succeeded under that number.
|
|
|
127
136
|
|
|
128
137
|
## Manual / emergency publish
|
|
129
138
|
|
|
130
|
-
`release.yml` also accepts `workflow_dispatch`, so you can trigger a build
|
|
131
|
-
|
|
139
|
+
`release.yml` also accepts `workflow_dispatch`, so you can trigger a build +
|
|
140
|
+
publish from the Actions UI without pushing a tag. The `github-release`
|
|
132
141
|
job will fail in that mode (no tag to attach to) — that's fine; the PyPI
|
|
133
142
|
publish itself will have already happened in `publish-pypi`.
|
|
134
143
|
|
|
135
144
|
If Trusted Publishing is broken for some reason and you need an emergency
|
|
136
145
|
release, generate a short-lived API token at
|
|
137
|
-
https://pypi.org/manage/account/token
|
|
146
|
+
<https://pypi.org/manage/account/token/> and run locally:
|
|
138
147
|
|
|
139
148
|
```bash
|
|
140
149
|
python -m build
|
|
@@ -79,7 +79,7 @@ Then just ask:
|
|
|
79
79
|
└─────────────┘ └────────────┘ └─────────────────┘
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
**Status: v0.
|
|
82
|
+
**Status: v0.9 (June 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP. The test suite covers schema, runner, MCP, kernel, notebook, run-index, subprocess-pool, and VS Code modules; CI also checks linting, type safety, schema generation, package metadata, and VSIX packaging. License: **MIT**.
|
|
83
83
|
|
|
84
84
|
Three workflows the current tree explicitly supports for end users and agents:
|
|
85
85
|
|
|
@@ -526,10 +526,17 @@ The `stata_required` marker tags the real-Stata integration tests. CI uses `pyte
|
|
|
526
526
|
|
|
527
527
|
## Contributing
|
|
528
528
|
|
|
529
|
+
Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for the
|
|
530
|
+
development setup, the checks CI runs, and PR guidelines. In short:
|
|
531
|
+
|
|
529
532
|
- Read [LICENSE-POLICY.md](LICENSE-POLICY.md) before opening a PR.
|
|
530
533
|
- Add a one-line acknowledgement to your first PR description; the template is in the policy file.
|
|
531
534
|
- Tests are required for any new schema field or runner behavior.
|
|
532
535
|
|
|
536
|
+
Bug reports and support questions go through
|
|
537
|
+
[GitHub issues](https://github.com/brycewang-stanford/stata-code/issues);
|
|
538
|
+
security reports go through [SECURITY.md](SECURITY.md).
|
|
539
|
+
|
|
533
540
|
---
|
|
534
541
|
|
|
535
542
|
## License
|
|
@@ -360,6 +360,7 @@ Stata's `r()` and `e()` return dictionaries, structurally separated. Each follow
|
|
|
360
360
|
| Field | Type | Notes |
|
|
361
361
|
| --- | --- | --- |
|
|
362
362
|
| `command` | `string \| null` | Mirrors `e(cmd)` when available; falls back to `last_estimation_cmd`. |
|
|
363
|
+
| `command_family` | `string \| null` | Coarse estimator family derived from the command name (`ols` / `iv` / `gmm` / `panel` / `count` / `did` / …); `null` when the command is unrecognized. |
|
|
363
364
|
| `depvar` | `string \| null` | Mirrors `e(depvar)`. |
|
|
364
365
|
| `n_obs` | `int \| null` | Integer form of `e(N)` when available. |
|
|
365
366
|
| `df_model` | `number \| null` | Mirrors `e(df_m)`. |
|
|
@@ -369,6 +370,7 @@ Stata's `r()` and `e()` return dictionaries, structurally separated. Each follow
|
|
|
369
370
|
| `ci_level` | `number` | Confidence level used for `ci_low` / `ci_high`; currently `95.0`. |
|
|
370
371
|
| `coefficients` | `array<Coefficient>` | One row per term in `e(b)`. |
|
|
371
372
|
| `model_stats` | `dict<str, number \| null>` | High-signal subset of `e()` scalars such as `N`, `df_m`, `df_r`, `r2`, `F`, `chi2`, `ll`, and `rmse`. Full scalars remain under `results.e.scalars`. |
|
|
373
|
+
| `diagnostics` | `dict<str, number \| null>` | Command-aware identification/specification statistics surfaced from `e()` (e.g. weak-ID F and Hansen J for `ivreg2`/`ivreghdfe`, AR(2)/Hansen for `xtabond2`, within-R² for `reghdfe`, `rho` for `xtreg`). Only scalars actually present in `e()` appear — never fabricated. |
|
|
372
374
|
|
|
373
375
|
**`Coefficient` shape:**
|
|
374
376
|
|
|
@@ -693,7 +695,7 @@ This section tracks how much of the schema is wired up in code. Not normative
|
|
|
693
695
|
`png` / `svg` / `pdf`; PNG `width` / `height` parsed from IHDR;
|
|
694
696
|
best-effort `source_command` / `source_line` attribution from the
|
|
695
697
|
submitted code. `inline` populated when `include_graphs="inline"`.
|
|
696
|
-
- Structured `error` —
|
|
698
|
+
- Structured `error` — 31-kind enum, `varname` / `path` / `name`
|
|
697
699
|
extracted from Stata's English error text by regex, structured
|
|
698
700
|
`context` (`{before, failing, after}`), `commands_executed` parsed
|
|
699
701
|
from pystata's multi-line transcript, `suggestions` generated by
|
|
@@ -144,8 +144,8 @@ remaining · ⬜ not started.
|
|
|
144
144
|
with structured results + MCP" converged across StatsPAI and rmcp. Defend by
|
|
145
145
|
positioning on **authoritative Stata-runtime fidelity**, not breadth.
|
|
146
146
|
- **Generic code-exec substitution.** A Jupyter-MCP + statsmodels sandbox can
|
|
147
|
-
"do econometrics" with zero domain tooling. Defense: *mandated Stata commands
|
|
148
|
-
|
|
147
|
+
"do econometrics" with zero domain tooling. Defense: *mandated Stata commands +
|
|
148
|
+
verifiable typed `e()` contracts* a generic sandbox cannot provide.
|
|
149
149
|
- **License contagion.** The two structured/MCP-native competitors (tmonk,
|
|
150
150
|
SepineTam) are AGPL; the kernels are GPL. To preserve our MIT clean-room
|
|
151
151
|
wedge we must never vendor their code paths (see `LICENSE-POLICY.md`).
|