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
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"name": "dk-workflows",
"source": "./",
"description": "dk-workflows",
"version": "1.2.1"
"version": "1.3.0"
}
]
}
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dk-workflows",
"version": "1.2.1",
"version": "1.3.0",
"description": "Portable repository workflows, configurable reviewers, and guarded drafting.",
"author": {
"name": "Dmitry Kropachev"
Expand Down
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dk-workflows",
"version": "1.2.1",
"version": "1.3.0",
"description": "Portable repository workflows, configurable reviewers, and guarded drafting.",
"author": {
"name": "Dmitry Kropachev"
Expand Down
5 changes: 5 additions & 0 deletions PROVENANCE.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@
}
],
"owned_changes": [
{
"source": "dk-code-factory/dk-workflows",
"version": "1.3.0",
"description": "Persistent Decisions storage, per-PR transactions, retained agreement evidence and independent-run recovery regressions."
},
{
"source": "dk-code-factory/dk-workflows",
"version": "1.2.0",
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# dk-workflows

Independent MIT plugin for Claude Code and Codex. Version 1.2.1.
Independent MIT plugin for Claude Code and Codex. Version 1.3.0.

## Install

Expand Down Expand Up @@ -245,3 +245,13 @@ one reassessment. Identical and supported operational refreshes use zero model c
affected/reused IDs and actual call counts. Review coverage, session identities, CI,
Decisions synchronization and iteration budgets retain their existing gates. See
[the preparation artifact contract](runtime/dk-pr-decisions/references/preparation.md).

Decisions can persist across independent runs by setting `DK_PR_DECISIONS_HOME` to
an absolute private directory shared by those runs. It is the complete cache root:
`<root>/<host>/<base-owner>/<base-repo>/pr-<number>.json`, including fork PRs.
When unset, the default remains `${XDG_DATA_HOME:-~/.local/share}/dk-pr-decisions`.
Explicit stores are exclusive; invalid or repository-local paths fail without
fallback. Hosts provide persistent storage and access. See the
[Decisions storage contract](runtime/dk-pr-decisions/references/storage.md) for
seeding, migration, locking and interruption recovery. Recovered choices require
live context refresh and engineering preparation before dependent work.
4 changes: 3 additions & 1 deletion runtime/dk-pr-decisions/procedure.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ Before drafting or revising decision text, read and follow [the decision languag

Use `python3 PLUGIN_ROOT/runtime/dk-pr-decisions/scripts/decisions.py --pr PR_URL COMMAND`. Always use the full PR URL for forks. `list` and `publish` require a full URL to locate the cache without discovery. Read [the API contract](references/api.md) for JSON fields, replacement details, and migration from the previous interface.

Read the [storage contract](references/storage.md) when configuring persistence or recovering a run. `DK_PR_DECISIONS_HOME` selects the complete private cache root across independent runs. Recovery restores agreements and history; always refresh live context and engineering preparation before dependent work. Never infer authorization, review coverage, preparation readiness or iteration budgets from a recovered cache.

Discussion analysis and description suggestions allow one correction for invalid
model JSON or evidence references. A second invalid result blocks the operation;
provider and authentication failures are not retried as formatting errors.

- `scan`: fetch paginated discussions, analyze changed text, and cache settled decisions and unresolved thread summaries. Does not publish unless explicitly invoked with `--publish`.
- `list`: read the cached snapshot without network requests, model calls, or cache writes. Run `scan` first if there is no cache. Results may be stale.
- `context`: refresh and export verified context without publishing. Save its JSON outside the repository for review and fix handoffs. Add `--local-decisions-file RUN_RECORD.json` for a `dk-pr-iter` run or a JSON array of local choices. Read active entries in `data.decisions`; superseded entries are history. An empty verified record is valid. Refresh after a new decision, body edit, or head change; stop dependent work if context is missing, stale, or conflicting.
- `context`: refresh and export verified context without publishing. Save its JSON outside the repository for review and fix handoffs. Temporary imports do not persist choices; explicitly select agreed PR-level choices through `add` or `replace` immediately, preserving exact user instructions or source evidence, then refresh context and preparation. Add `--local-decisions-file RUN_RECORD.json` for a `dk-pr-iter` run or a JSON array of local choices. Read active entries in `data.decisions`; superseded entries are history. An empty verified record is valid. Refresh after a new decision, body edit, or head change; stop dependent work if context is missing, stale, or conflicting.
- `prepare --input-manifest MANIFEST.json --output-dir PRIVATE_DIR`: reconcile complete evidence into a separately versioned engineering preparation artifact. Read [the preparation procedure and artifact contract](references/preparation.md) before assembling inputs. Preparation governs scope, remediation depth, performance, compatibility, complexity, code/test placement and proportionate validation before initial work or review. It does not publish.
- `suggest [--source code|description|all]`: optionally discover candidates without recording or publishing them. The default is `code`, which inspects the complete PR patch and can be costly on large PRs. Use `description` for description-only candidates, or `add` to record an already-established choice. Code discovery retains the complete pinned patch, permalink ranges, and existing decisions in private files beside the decision cache and gives the analysis process a compact manifest for bounded reads. Whole-PR discovery requires inspecting the complete patch; unavailable inspection blocks discovery without deleting recorded choices. Code-discovery requests have a conservative serialized-size limit; provider failure messages are bounded. Description candidates come from outside the existing Decisions section. Suggestions alone do not establish agreement.
- `add --json '{"text":"...","references":["EXACT_URL"]}'`: record a selected decision locally. Use exact current discussion URLs or an exact cached code/description suggestion. For a choice authorized directly by the user without a URL, pass `--user-instruction 'exact user instruction'` with an empty references array.
Expand Down
6 changes: 3 additions & 3 deletions runtime/dk-pr-decisions/references/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ All commands return one JSON object:
- `text`: choice text, without the generated `**Choice:**` prefix.
- `source_type`: `description`, `discussion`, `code`, `user`, or `local`.
- `references`: exact source URLs; empty for a directly authorized user choice or local handoff.
- `source`: user instruction, local evidence, description snapshot hash, or null when references supply the source.
- `source`: exact user instruction, local evidence, retained description/discussion evidence (JSON text including the original snapshot), or null when only references are available in older records. Changed or deleted discussion sources include original agreement evidence alongside current comments (null for deleted comments), so preparation must reconcile the change.
- `status`: `active`, `candidate`, or `superseded`.
- `publication_status`: `published` or `unpublished`, based on the fetched/cached description.
- `superseded_by`: replacement ID for historical entries, otherwise null.

Existing Decisions entries are read as Markdown blocks, including multiline bullets and standalone paragraphs. Their text is preserved rather than rewritten by analysis. Entries from discussions that have identical normalized text share an ID with the corresponding description entry. Different wording remains distinct; reconcile a changed agreement explicitly with `replace`.
Existing Decisions entries are read as Markdown blocks, including multiline bullets and standalone paragraphs. Their text is preserved rather than rewritten by analysis. Entries from discussions that have identical normalized text share an ID with the corresponding description entry. Different wording remains distinct; reconcile a changed agreement explicitly with `replace`. Saved agreements survive source edits and deletion; repeated recording preserves the first evidence. Missing evidence in an older cache cannot be reconstructed retroactively.

`context` includes `pr_url`, `head_sha`, `body_hash`, and `verified` in `data`, plus the unified records. It retains `live_decisions`, `discussion_decisions`, and `local_decisions` as compatibility evidence. Use active unified records for current constraints; the raw live section can contain superseded history. `list` describes a cached snapshot and makes no freshness claim. `suggest` returns candidates only; use `add` or `replace` to select one before publication.

Expand All @@ -46,7 +46,7 @@ The live body/head comparison is best effort, not an atomic GitHub compare-and-s

## Migration

Previously `scan` and `add` published automatically. Now use `scan --publish`, or run `publish` after `scan`, `add`, or `replace`. Previously `list` refreshed; now run `scan` when fresh data is needed. Existing cache files remain readable.
Previously `scan` and `add` published automatically. Now use `scan --publish`, or run `publish` after `scan`, `add`, or `replace`. Previously `list` refreshed; now run `scan` when fresh data is needed. Existing cache files remain readable. See the [storage contract](storage.md) for an exclusive persistent root, migration and recovery.

All former top-level command results now live under `data`; publication results always live under `publication`. Consumers should inspect `schema_version` and `status` before reading `data`. The PR review runner accepts the new context envelope and legacy context files.

Expand Down
69 changes: 69 additions & 0 deletions runtime/dk-pr-decisions/references/storage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Decisions storage and recovery

Set `DK_PR_DECISIONS_HOME` to an absolute private directory accessible to every
run that should share agreements. This is the root of the complete Decisions
cache, not its parent. Records use
`<root>/<host>/<base-owner>/<base-repo>/pr-<number>.json`. The PR URL supplies the
base identity, including when the checkout and head belong to a fork. Hosts,
repositories and PRs have independent records. The comments report, suggestion
evidence and publication receipts use the same store.

When the variable is unset, the root remains
`${XDG_DATA_HOME:-~/.local/share}/dk-pr-decisions`. An explicitly empty, relative,
inaccessible or repository-local store fails with a diagnostic. A corrupt record
also blocks use; restore a valid backup or reconcile it explicitly. There is no
silent fallback or merging with another store. Hosts must provide persistent
storage, sandbox access and a filesystem supporting process locks, atomic rename
and synchronization. No Code Factory configuration is changed by this plugin.

Every modifying command holds a per-PR process lock from live snapshot refresh
through analysis, local changes and publication bookkeeping. PRs can proceed
independently. New directories are private (0700); records and locks use 0600.
Atomic replacement synchronizes the file and containing directory. Interruption
leaves the previous complete record or its committed replacement. Temporary files
from a killed process are not read as records. Do not delete lock files while
workflows may be active. `list` reads offline without creating directories, locks
or records, and makes no freshness claim.

Recovery automatically retains recorded choices, exact agreement evidence and
replacement chains across independent runs, even with disposable `XDG_DATA_HOME`
directories. Repeated recording does not overwrite the original evidence.
Mutable source edits or deletion do not silently remove an agreement: retained
evidence and current sources must be reconciled through fresh context and the
existing engineering preparation process. Material conflicts block dependent
work. Use explicit `replace` for a changed agreement; a superseded ID cannot be
reactivated. Legacy records retain the evidence they already contain; exact text
that was never cached cannot be recovered.

Recovery grants no publication authority, preparation readiness, review coverage
or iteration budget. Fetch live scope/head/discussions, refresh verified context
and run preparation before dependent work. Fresh review and iteration requests
keep their existing session and budget rules. Iteration records remain operational
history. `--local-decisions-file` is a temporary context import and never persists
its choices. Suggestions and unresolved questions remain unagreed until selected
through `add` or `replace`.

Saving and recovering cache records never mutates GitHub. Publication remains an
explicit separate action (`publish` or `scan --publish`). A pending publication
receipt survives interruption and refresh. Use `publish --reconcile` to observe
live state before any retry; do not discard uncertain receipts or replay writes.

## Migration

Existing Decisions JSON formats and API v2 records remain readable. With the
default root, the former `dk-pr-read-comments` cache is still migrated on refresh.
An explicit root never searches the default or former report store.

Before workflows start, stop writers and seed an **empty** persistent root by
copying the contents of the existing `dk-pr-decisions` root, retaining the
host/owner/repository hierarchy and private permissions. Include all companion
evidence files and publication bookkeeping. Configure the same absolute
`DK_PR_DECISIONS_HOME` for every independent run and verify recovery with `list`,
then refresh context and preparation. Keep a backup of the original store.

Do not overlay or merge divergent JSON snapshots. Select one authoritative seed,
reconcile uncertain publications against live GitHub, and replay other agreed
choices with `add` or `replace`, supplying the exact original instruction or source
evidence. Reconcile changed or missing mutable sources through preparation before
dependent work. This preserves replacement history and prevents an old snapshot
from reactivating superseded choices.
Loading
Loading