OH MY PM v0.6.1
OH MY PM v0.6.1
Application boundary completion.
An internal architecture release. Every command, flag, output format, exit code,
and MCP schema is unchanged — if you upgrade and change nothing, nothing behaves
differently. What changed is where the shared work lives.
Why this release exists
v0.5.4 introduced ApplicationResult<T>: a shared envelope describing where a
result came from, what diagnostics it carried, and when it was produced. It was
correct and complete, and nothing used it. Outside its own definition and test
it had two references, both re-exports.
At the same time packages.json declared:
The four SHARED project workflows (brief/risks/next/handoff) go through the
application boundary on both surfaces.
That was not true. The MCP server called the shared use case. The CLI called
only the shared document loader, then re-composed the Runtime, provider, and
Kernel itself. The two surfaces shared the first step of the pipeline and
duplicated the rest, arriving at the same answer by two different routes.
Two routes that must agree, with nothing enforcing agreement, is a drift waiting
to happen. This release closes it.
Changed
- The CLI now calls
runLocalProjectWorkflowforbrief,risks,next,
andhandoff— the same use case the MCP server calls. It composes no
Runtime, provider, or Kernel for them. - The shared workflows are describable as
ApplicationResult<T>.
runLocalProjectApplicationandrunGitHubProjectApplicationwrap the
existing use cases and return the envelope, with a schema version, a stable
operation name, an injected-clock timestamp, a normalized source descriptor,
and structured diagnostics. - A minimal
ExecutionContextcarries the correlation id, the injected
clock, and an optional cancellation signal. - GitHub workflows accept cancellation. Checked at the last offline point
and again after the request returns. tools/validate-application-boundary.mjsruns inpnpm validateand in
CI, and fails if the boundary claim stops holding in either direction.- One fixed-time constant. The CLI's
LOCAL_FIXED_NOWis gone; both
surfaces use the application'sFIXED_LOCAL_INSTANT. They always held the
same value for the same reason.
Unchanged
Everything a user or an MCP client can observe:
| Surface | Guarantee |
|---|---|
| CLI commands & flags | identical |
| CLI JSON output | byte-identical |
| CLI Markdown output | byte-identical |
| CLI exit codes | identical |
| MCP tool names/order | identical |
| MCP schemas | identical |
| Provider diagnostics | identical |
| Project Memory | no format change, no migration |
| Command families | omp canonical, ohmypm compatibility, oh-my-pm deprecated |
This is asserted, not asserted-to. tests/e2e/public-golden.test.ts replays a
29-entry recording captured from the v0.6.0 tree — stdout, stderr, exit codes,
and MCP payloads — and compares the actual bytes. It was captured before any
refactor began, so it describes v0.6.0 behaviour and cannot be adjusted after
the fact to match whatever the new code happens to produce.
What deliberately did not move
status, doctor, and plan stay outside the application boundary.
Each has exactly one presentation consumer. They appear only under cli/src/
and are absent from both MCP operation unions. Moving them would buy diagram
symmetry and no reuse, and would put a second surface's worth of contract on
commands nothing else calls. The CLI keeps a local Runtime for them, and that is
the asymmetry packages.json documents.
The validator enforces this in both directions: it fails if a shared workflow is
re-composed per surface, and if a CLI-only command is pushed through the
boundary.
Also deliberately unmoved:
- Provider diagnostic report shapes.
ProviderStatusReportand
ProviderDoctorReportstay as they are. Replacing them with the unified
Diagnosticmodel would change MCP output, and compatibility outranks
uniformity. - Low-level helpers. A pure function still returns whatever it returns.
Nothing is forced into the envelope to make a diagram tidy. - The raw
RuntimeResponse. It stays out of the envelope. It is
runtime-shaped, and putting it in a result both surfaces serialize would make
an internal type part of a public contract.
Cancellation scope
Only the GitHub workflows. They are the ones doing remote, potentially
long-running work.
Local workflows read a bounded set of configured Markdown documents. Adding
cancellation machinery to a fast, finite filesystem walk would be complexity
with no caller, so the local family takes no signal.
Two properties hold where it is implemented:
- A cancellation before the request means no transport is built and no token is
read. - A cancellation during the request is still a failure. The already-fetched
payload is discarded rather than returned. Reporting data the caller asked us
to stop fetching would make cancellation meaningless.
github_cancelled is a new public failure code in a new cancelled category:
retryable (nothing about the request was wrong), exit code 2 (not our defect and
not a bad request), and not an MCP protocol error (the caller asked for it).
Safety properties
Source descriptors and diagnostics carry no token, authorization header, raw
transport object, or resolved absolute path. A caller-supplied project root is
echoed back exactly as typed — a relative root stays relative, so an error
message never discloses where the repository actually lives.
The free-text GitHub search query is deliberately omitted from source metadata:
kind and limit already describe the search, and echoing caller text into a
descriptor both surfaces serialize would widen what a result can carry for no
identification benefit.
generatedAt comes only from the injected clock. Under a fixed clock a result
is byte-reproducible.
Verification
| Check | Result |
|---|---|
| Unit tests | 3027 passed / 196 files |
| Golden replay | 31 passed, byte-identical |
| Boundary mutation tests | 9 passed |
| Validators | 10/10 OK |
| Build (incl. Rust/WASM) | pass |
| Lint / format / rustfmt / clippy | pass |
The boundary validator reported five failures — naming exactly the CLI
duplication — before the convergence commit, and passes after it. The nine
mutation tests damage a sandboxed copy of the repository in each way the
validator claims to detect and assert it fails for the right reason, so the
check is load-bearing rather than decorative.
Not in this release
- No Project Memory format change, migration, or data movement.
- No Dashboard, and no Dashboard groundwork.
- No cloud sync, telemetry, accounts, or remote storage.
- No new command, flag, or MCP tool.
- No dependency upgrade taken as part of the release.
Next
v0.6.2 hardens Project Memory and local governed data: atomic writes, integrity
metadata, a schema migration framework, cross-process locking, path confinement,
and corruption detection with preview-first repair.