Read a local plan before answering

The maude-plan-consultation/v1 profile lets an external caller inspect one user-created Maude Plan Core draft without modifying the database.

Integration release 0.1.0-alpha.1: public-source reproduction and an independent public-only newcomer attempt passed. See the release and source tag and release notes. This versions one tested profile, not family-wide readiness.

Fixed public inputs

This alpha profile was reproduced on Linux x86-64 with Ubuntu 24.04.4 LTS, CPython 3.12.3, pip 24.0 and SQLite 3.45.1. It uses:

Allow 150 MiB in a new directory. Setup requires CPython 3.12, Git and network access to GitHub and PyPI. It reads no provider credential, starts no service and creates no plan.

Set up, create and inspect

git init constellation-site
git -C constellation-site remote add origin https://github.com/unpingable/unpingable-site.git
git -C constellation-site sparse-checkout init --no-cone
git -C constellation-site sparse-checkout set /constellation/examples/
git -C constellation-site fetch --filter=blob:none --depth=1 origin 013b05d0c5258ee1bc898a51b271e47d49c4f865
git -C constellation-site checkout --detach FETCH_HEAD
test "$(git -C constellation-site rev-parse HEAD)" = 013b05d0c5258ee1bc898a51b271e47d49c4f865
cd constellation-site
PARENT=$(mktemp -d /tmp/maude-plan-reader.XXXXXX)
RUN="$PARENT/profile"
bash constellation/examples/setup_maude_reader.sh "$RUN"

STORE="$RUN/plans.sqlite"
WORKSPACE="$RUN/user-workspace"
mkdir "$WORKSPACE"
"$RUN/venv/bin/maude-plan" --store "$STORE" new \
  --draft-id user-draft \
  --goal 'Inspect the current local plan before answering a maintenance question' \
  --workspace "$WORKSPACE" --author external-caller > "$RUN/created-draft.json"

python3 constellation/examples/read_maude_plan.py \
  --maude-plan "$RUN/venv/bin/maude-plan" \
  --store "$STORE" --draft-id user-draft

The final command emits one compact JSON object. Expect schema to be constellation.maude-plan-inspection/v1, availability to be available, and the requested draft_id. A new draft has check_summary: "never_checked" and last_lock_receipt_id: null; its revision and plan digests are generated values.

The creation output contains the full plan, including its goal and workspace path. Keep created-draft.json private; do not paste it into an issue. The reader's smaller JSON is the starting point for a diagnostic excerpt, still subject to redacting sensitive identifiers.

setup caller → Maude CLI new → caller-owned store
external reader → Maude CLI --read-only inspect → same store
external reader ← revision and check/lock summary ← Maude
{"availability":"available","check_summary":"never_checked","draft_id":"user-draft","last_lock_receipt_id":null,"plan_digest":"sha256:…","revision_id":"sha256:…","schema":"constellation.maude-plan-inspection/v1"}

Keep writers quiescent during inspection. Maude assembles the projection through separate database reads, so a concurrent writer can produce a mixed-time aggregate even in one invocation.

Restart, refusal and recovery

To verify process-independent persistence, run the reader again in a new shell or process with the same RUN, STORE and draft ID. The revision and plan digests should match while no writer changes the draft.

--read-only permits only list and inspect. A mutating command refuses with CLI exit status 2 before opening the store:

"$RUN/venv/bin/maude-plan" --store "$STORE" --read-only lock user-draft
# expected: refusal; exit 2

An absent draft or incompatible store is reported by the reader as availability: "unavailable" with reason: "command_refused"; the CLI has no typed absence result, so the adapter does not infer one. If the configured program is missing, the reason is program_unavailable. The reader deliberately exits 0 after emitting either available or unavailable JSON: automation must parse availability and reason, not use its process status as the result.

{"availability":"unavailable","draft_id":"user-draft","reason":"command_refused","schema":"constellation.maude-plan-inspection/v1"}
{"availability":"unavailable","draft_id":"user-draft","reason":"program_unavailable","schema":"constellation.maude-plan-inspection/v1"}

Recovery is non-destructive: correct the program or store path, leave the owner database in place, then rerun the reader. It makes no automatic retry and never constructs a replacement response. Preserve an unexpected store and inspect the bounded reason before taking another action.

# Missing owner store: unavailable/command_refused, without creating the path.
python3 constellation/examples/read_maude_plan.py \
  --maude-plan "$RUN/venv/bin/maude-plan" \
  --store "$RUN/absent/plans.sqlite" --draft-id user-draft
test ! -e "$RUN/absent"
# Unavailable program: no answer about the plan can be established.
python3 constellation/examples/read_maude_plan.py \
  --maude-plan "$RUN/no-program" --store "$STORE" --draft-id user-draft
# Recovery: inspect the original store using the correct program, not new/check/lock.
python3 constellation/examples/read_maude_plan.py \
  --maude-plan "$RUN/venv/bin/maude-plan" --store "$STORE" --draft-id user-draft

Timeout, oversized output, invalid JSON and incompatible schemas also return unavailable; the caller must not answer as if the read succeeded. These boundary cases have component-test evidence, not simulated success in the public walkthrough. No effect is dispatched in this profile, so unavailable consultation is not an uncertain execution or a settlement result.

Ownership, lifecycle and limits

The user owns the Plan Core database and draft. Maude owns the revision and lifecycle projection schemas. The small reader is an external caller: it validates and reduces the projection but receives no authority to check, lock, compile or execute the plan. Read-only mode preserves database contents through its SQLite connection; it does not promise that SQLite creates no sidecar activity.

This profile demonstrates recorded local inspection after caller restart. It does not establish external truth, current deployment state, plan validity, authorization, execution, AG or Docket integration, model-assisted authoring, or connected-cache behavior. Cross-store backup, restore, migration and rollback have not been verified.

Disposable cleanup and support

After saving anything you need, inspect the exact temporary directory printed in PARENT. If it contains only this disposable exercise, you may remove that directory using your normal file manager. This removes its environment, source checkout, installation reports, workspace and plan database, not the separately cloned example kit. Do not remove retained user records:

printf '%s\n' "$PARENT"
ls -ld -- "$RUN" "$STORE" "$WORKSPACE"

These pathname checks and the installed reader work locally. The source checkouts are sparse partial clones: optional git status or other Git operations can fetch additional objects and require GitHub access. Do not make successful Git inspection a prerequisite for reading retained local state offline. If source verification is needed, retain the installation and perform it when the public source is reachable; do not delete records to resolve a download error.

For a minimal report, include the two public revisions above, OS/Python/SQLite versions, the command used, and the reader's JSON with local paths redacted. Do not include credentials or private plan text. Use the support guide or the public Maude issue tracker. Support is best effort with no guaranteed response time.

See the immutable release manifest, sanitized qualification record and release policy.