projmux 0.15.2 → 0.16.0
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.
- package/README-ko.md +3 -4
- package/README.md +3 -3
- package/docs/agent-message-replies.md +82 -2
- package/docs/ai-agent-shortcuts.md +6 -5
- package/docs/architecture.md +149 -63
- package/docs/claude-coordination-endpoints.md +192 -21
- package/docs/cli-guide.md +322 -124
- package/docs/cli.md +605 -500
- package/docs/codex-installed-compatibility.md +6 -11
- package/docs/codex-native-required-migration.md +1 -59
- package/docs/configuration.md +164 -176
- package/docs/globalization.md +11 -1
- package/docs/heterogeneous-dialogue-canary.md +8 -3
- package/docs/hooks.md +83 -32
- package/docs/keybindings.md +108 -3
- package/docs/legacy-cli-retirement.md +3 -3
- package/docs/legacy-diagnostics-inventory.md +4 -4
- package/docs/native-picker.md +3 -5
- package/docs/notify-queue.md +1 -1
- package/docs/operational-diagnostics.md +53 -31
- package/docs/pr-guideline.md +66 -22
- package/docs/release.md +97 -0
- package/docs/replacement-contract.md +66 -58
- package/docs/resource-attribution.md +2 -2
- package/docs/session-restore.md +46 -80
- package/docs/settings-ia.md +43 -20
- package/docs/statusbar.md +25 -22
- package/docs/testing.md +15 -0
- package/docs/theme-palette.md +14 -0
- package/docs/tmux-surface-inventory.md +8 -10
- package/docs/troubleshooting.md +2 -4
- package/docs/upgrading.md +142 -7
- package/docs/usage-tracking.md +56 -53
- package/package.json +5 -5
- package/docs/agent-workflow.md +0 -2123
- package/docs/codex-generation-pool.md +0 -623
- package/docs/codex-stored-qualification.md +0 -45
package/docs/pr-guideline.md
CHANGED
|
@@ -59,33 +59,70 @@ classifies the whole PR by its title type, not by content.
|
|
|
59
59
|
|
|
60
60
|
## PR body
|
|
61
61
|
|
|
62
|
-
Use this template
|
|
62
|
+
Use this template. Keep all six sections in this order.
|
|
63
|
+
[`.github/pull_request_template.md`](../.github/pull_request_template.md)
|
|
64
|
+
pre-fills new PRs with the same template; keep the two in sync when either
|
|
65
|
+
changes.
|
|
63
66
|
|
|
64
67
|
```markdown
|
|
65
68
|
## Summary
|
|
66
|
-
- 1–3 bullets
|
|
67
|
-
|
|
68
|
-
##
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
-
|
|
69
|
+
- What changed, in 1–3 bullets.
|
|
70
|
+
|
|
71
|
+
## Background
|
|
72
|
+
- Why this is needed: the problem, a reproduction, related issues or PRs.
|
|
73
|
+
|
|
74
|
+
## Changes
|
|
75
|
+
- Behavior and code changes, grouped by area.
|
|
76
|
+
- Breaking: what breaks and how to migrate (if any).
|
|
77
|
+
|
|
78
|
+
## Scope
|
|
79
|
+
- In scope:
|
|
80
|
+
- Out of scope (and follow-ups):
|
|
81
|
+
|
|
82
|
+
## Verification
|
|
83
|
+
- [ ] Fast local gates: `make fmt` → `make fix` → `make test`
|
|
84
|
+
- [ ] Long local gates: `make test-integration` → `make test-e2e`
|
|
85
|
+
- [ ] Required CI checks green
|
|
86
|
+
- [ ] Manual steps (if relevant):
|
|
87
|
+
- Globalization (check exactly one):
|
|
88
|
+
- [ ] No user-facing string changes.
|
|
89
|
+
- [ ] User-facing strings are behind `internal/i18n` catalog keys with tests.
|
|
90
|
+
- [ ] Non-translated strings are classified as literal/data/debug-only.
|
|
91
|
+
|
|
92
|
+
## Measurements
|
|
93
|
+
- (If relevant) before/after numbers, method, environment, run ids.
|
|
94
|
+
Mark each number as observed or inferred.
|
|
77
95
|
```
|
|
78
96
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- **
|
|
82
|
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
Per-section rules:
|
|
98
|
+
|
|
99
|
+
- **Summary** — the short version a reviewer reads first. The diff already
|
|
100
|
+
shows the code; say what changed in terms of behavior.
|
|
101
|
+
- **Background** — **why** matters more than **what**. State the problem, how
|
|
102
|
+
to reproduce it, and related issues or PRs. Reference issues with
|
|
103
|
+
`Closes #<n>` so they auto-close on merge.
|
|
104
|
+
- **Changes** — group by area rather than by file. Any breaking change must be
|
|
105
|
+
listed here with a migration note, and the title must also carry `!` or the
|
|
106
|
+
body a `BREAKING CHANGE:` footer (see the title rules above).
|
|
107
|
+
- **Scope** — say what is deliberately left out and name the follow-ups
|
|
108
|
+
(issue or PR) instead of leaving deferred work implicit.
|
|
109
|
+
- **Verification** — list the gates in the order
|
|
110
|
+
[AGENTS.md](../AGENTS.md) runs them: fast local gates, then the long local
|
|
111
|
+
gates (which may still be running while CI runs on the published head), then
|
|
112
|
+
the required CI checks, then any manual steps. For any new or changed
|
|
113
|
+
user-facing text, check exactly one Globalization item. Normal UX copy needs
|
|
114
|
+
a catalog key and test coverage. Commands, paths, config keys, env vars,
|
|
115
|
+
provider payloads, locale enum values, product names, debug logs, and
|
|
116
|
+
internal diagnostics may stay out of the catalog only when explicitly
|
|
117
|
+
classified in the PR body.
|
|
118
|
+
- **Measurements** — fill it when the PR claims a change in speed, size, or
|
|
119
|
+
resource use (for example a `perf` PR). Give the method, environment, and
|
|
120
|
+
run ids so the numbers can be reproduced, and mark which values were
|
|
121
|
+
observed and which inferred.
|
|
122
|
+
|
|
123
|
+
For small PRs, **Background** and **Measurements** may be written as `N/A`
|
|
124
|
+
with a one-line reason. Do not delete them, so the section order stays the
|
|
125
|
+
same across PRs.
|
|
89
126
|
|
|
90
127
|
## Branch protection in effect
|
|
91
128
|
|
|
@@ -95,6 +132,13 @@ Notes:
|
|
|
95
132
|
- Required status checks are the five CI job names `Format`, `Unit Tests`,
|
|
96
133
|
`NPM Packages`, `Integration Tests`, and `E2E Tests`. The aggregate `Test`
|
|
97
134
|
job is observed as the project-wide fan-in, but it is not ruleset-required.
|
|
135
|
+
- A required check is a job *name*. Renaming or splitting one of those five
|
|
136
|
+
stops that context from ever being reported, and GitHub holds the PR at
|
|
137
|
+
`expected` forever: every check green, merge blocked. Keep a thin aggregate
|
|
138
|
+
job under the original name with `needs: [<new jobs>]` and `if: always()`.
|
|
139
|
+
Without `if: always()` the job skips on child failure, which is neither green
|
|
140
|
+
nor red. `test/e2e/shard-contract.sh` fails when the `E2E Tests` aggregate is
|
|
141
|
+
missing.
|
|
98
142
|
- Admin bypass is `pull_request` mode — admin can self-merge without
|
|
99
143
|
approvals, but the PR itself is mandatory.
|
|
100
144
|
- Linear history is enforced. The merge methods exposed are
|
package/docs/release.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Release
|
|
2
|
+
|
|
3
|
+
This document describes how a projmux version is released. For the npm
|
|
4
|
+
package layout, publish order, and trusted publishing, see
|
|
5
|
+
[npm-distribution.md](npm-distribution.md). For the PR title rules that feed
|
|
6
|
+
the release notes, see [pr-guideline.md](pr-guideline.md).
|
|
7
|
+
|
|
8
|
+
## Stable releases through release-please
|
|
9
|
+
|
|
10
|
+
`release-please-action` watches `main`, accumulates Conventional Commit
|
|
11
|
+
subjects, and opens or refreshes a "chore(main): release X.Y.Z" PR. That PR
|
|
12
|
+
contains the version bump (`internal/version/version.go` and
|
|
13
|
+
`.release-please-manifest.json`), the `CHANGELOG.md` updates, and the release
|
|
14
|
+
notes.
|
|
15
|
+
|
|
16
|
+
Merging the release PR creates the GitHub Release with auto-generated notes as
|
|
17
|
+
a **draft** (`draft` in `release-please-config.json`).
|
|
18
|
+
|
|
19
|
+
## Tag creation
|
|
20
|
+
|
|
21
|
+
The same package config sets `force-tag-creation`, so release-please creates
|
|
22
|
+
`refs/tags/vX.Y.Z` during its release pass, before it computes the next release
|
|
23
|
+
PR. That tag creation triggers the tag workflow through the release-please PAT.
|
|
24
|
+
|
|
25
|
+
Do not move tag creation into a post-action workflow step. release-please-action
|
|
26
|
+
creates releases before pull requests, and a delayed tag makes the same run
|
|
27
|
+
treat the just-released commits as unreleased.
|
|
28
|
+
|
|
29
|
+
## The tag workflow
|
|
30
|
+
|
|
31
|
+
`.github/workflows/release.yml` triggers on the tag push. It runs the shipped
|
|
32
|
+
E2E shard/suite matrix behind the fail-closed `Release E2E Tests` aggregate,
|
|
33
|
+
then builds the linux/darwin × amd64/arm64 matrix and uploads tarballs to the
|
|
34
|
+
drafted release (`gh release upload --clobber`). `Build Release` depends on the
|
|
35
|
+
aggregate rather than on individual shards.
|
|
36
|
+
|
|
37
|
+
Do not add hardcoded notes back to that workflow. release-please owns the
|
|
38
|
+
notes.
|
|
39
|
+
|
|
40
|
+
## Publish ordering
|
|
41
|
+
|
|
42
|
+
The release becomes visible only in the final `publish-release` job, after
|
|
43
|
+
`publish-npm` succeeds. That ordering is the contract:
|
|
44
|
+
|
|
45
|
+
- Users never see a GitHub release for a version npm cannot install yet.
|
|
46
|
+
- A failed npm publish leaves the release drafted and the workflow red instead
|
|
47
|
+
of shipping a half-published version.
|
|
48
|
+
|
|
49
|
+
See [npm-distribution.md](npm-distribution.md#publish-order) for the npm side
|
|
50
|
+
of that order.
|
|
51
|
+
|
|
52
|
+
## Release candidates
|
|
53
|
+
|
|
54
|
+
Release candidates are cut **outside** release-please, by the
|
|
55
|
+
`workflow_dispatch`-only `.github/workflows/release-rc.yml`. It takes an
|
|
56
|
+
`X.Y.Z-rc.N` version, drafts a GitHub Release marked `--prerelease` against
|
|
57
|
+
`main` HEAD, then pushes `vX.Y.Z-rc.N` with the release-please PAT, so the same
|
|
58
|
+
`release.yml` builds, uploads, and publishes it.
|
|
59
|
+
|
|
60
|
+
Running it is a deliberate manual act: npm publishes cannot be recalled.
|
|
61
|
+
|
|
62
|
+
### Do not configure prerelease in release-please
|
|
63
|
+
|
|
64
|
+
Do **not** add `prerelease` or `prerelease-type` to `release-please-config.json`
|
|
65
|
+
to get release candidates. release-please gates the prerelease flag on
|
|
66
|
+
`config.prerelease && (version.preRelease || version.major === 0)`. This
|
|
67
|
+
repository is `0.x`, so the key would stamp *stable* releases as prereleases,
|
|
68
|
+
`releases/latest` would stop resolving, and default-channel updates would go
|
|
69
|
+
silently dead.
|
|
70
|
+
|
|
71
|
+
### The rc path never touches the manifest
|
|
72
|
+
|
|
73
|
+
The rc path writes exactly one ref: the tag. It never touches
|
|
74
|
+
`.release-please-manifest.json`, so release-please keeps measuring the next
|
|
75
|
+
stable release from the previous *stable* release.
|
|
76
|
+
|
|
77
|
+
release-please picks that boundary by matching the manifest value against a
|
|
78
|
+
tag, with no prerelease filter on that path. An rc holding the manifest slot
|
|
79
|
+
would silently trim the next stable release notes and its `compare/` link.
|
|
80
|
+
|
|
81
|
+
## Channel branching in release.yml
|
|
82
|
+
|
|
83
|
+
`release.yml` branches on the tag only where the channel is decided:
|
|
84
|
+
|
|
85
|
+
- A prerelease tag publishes npm with `--tag rc` and keeps `--prerelease` when
|
|
86
|
+
the release is undrafted.
|
|
87
|
+
- A stable tag runs exactly as before.
|
|
88
|
+
|
|
89
|
+
Job names, order, and the `publish-npm` → `publish-release` gating are
|
|
90
|
+
identical for both. `test/release_workflow_contract_test.py` executes both step
|
|
91
|
+
scripts against a stable and an rc tag to hold that split.
|
|
92
|
+
|
|
93
|
+
## Commit subjects
|
|
94
|
+
|
|
95
|
+
Non-Conventional commit subjects on `main` are silently skipped by
|
|
96
|
+
release-please. Keep PR titles strict. Squash merge ensures the PR title is the
|
|
97
|
+
only subject that lands.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Replacement completion and restorability
|
|
2
2
|
|
|
3
3
|
Three layers of this application hold an execution image, and every consumer of
|
|
4
|
-
`make install`, `npm install`, or a provider
|
|
4
|
+
`make install`, `npm install`, or a provider upgrade believes one
|
|
5
5
|
sentence about all three at once. That sentence is false in a different way on
|
|
6
6
|
each layer. This document fixes what is guaranteed, what is not, and how a
|
|
7
7
|
report can be recovered from the tokens the diagnosis prints.
|
|
@@ -13,7 +13,7 @@ the `projmux doctor` replacement table:
|
|
|
13
13
|
| --- | --- | --- |
|
|
14
14
|
| `L1` | `installed-executable-image` | the file the installed path publishes |
|
|
15
15
|
| `L2` | `long-lived-projmux-processes` | every running child of that file |
|
|
16
|
-
| `L3` | `provider-sessions-and-generations` | provider sessions
|
|
16
|
+
| `L3` | `provider-sessions-and-generations` | provider sessions, whose app-server lifetime the upstream `codex app-server daemon` owns |
|
|
17
17
|
|
|
18
18
|
`projmux doctor` renders the table on an unfiltered run and under
|
|
19
19
|
`projmux doctor --section replacement`. It is read-only in the same sense as
|
|
@@ -44,22 +44,14 @@ image accepts no new work on any of the three layers*.
|
|
|
44
44
|
replace it and is left alone — see *The L2 replacement policy* below. A
|
|
45
45
|
replacement that has not finished within the drain cutoff is reported as
|
|
46
46
|
`replacement-cutoff-reached` and is still not ended.
|
|
47
|
-
- `L3`
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
measures a declared pair in isolation and
|
|
56
|
-
`projmux agent app-server upgrade qualify --receipt <absolute-json>` installs
|
|
57
|
-
the receipt it writes where both doors read it. **What is not guaranteed is
|
|
58
|
-
the measurement's honesty.** The gate checks that the receipt's coverage
|
|
59
|
-
counters can have come from a run — an acceptance claim with no observation
|
|
60
|
-
behind it is refused as forged — but a determined forger who writes a coverage
|
|
61
|
-
count of one is not contradicted by anything else in the receipt. The gate
|
|
62
|
-
makes the receipt state its coverage; it does not attest to it.
|
|
47
|
+
- `L3` is not replaced by an install at all, and this application no longer
|
|
48
|
+
switches an app-server generation: the endpoint lifetime belongs to the
|
|
49
|
+
upstream `codex app-server daemon`, and the private generation pool that once
|
|
50
|
+
owned it — with its upgrade, qualification, and handover commands — is gone.
|
|
51
|
+
What the row still reports is the Registry against provider evidence: a
|
|
52
|
+
`Running` Agent that provider evidence contradicts, and a `Running` Agent that
|
|
53
|
+
nothing can confirm. Absence of both is not evidence of a restore route, so
|
|
54
|
+
restoration stays `unknown`.
|
|
63
55
|
|
|
64
56
|
**Non-Guarantee.** Explicitly outside this contract:
|
|
65
57
|
|
|
@@ -68,13 +60,14 @@ image accepts no new work on any of the three layers*.
|
|
|
68
60
|
`unsupported-platform` with the `unknown` verdict on both axes. This contract
|
|
69
61
|
does not build a substitute observation for that platform; it states the gap.
|
|
70
62
|
- The provider's own upstream seamless-upgrade contract. `L3` reasons about the
|
|
71
|
-
|
|
63
|
+
Registry and the provider evidence it can reach, never about what the provider
|
|
64
|
+
promises.
|
|
72
65
|
- An externally owned (`unmanaged`) app-server. Its state is not this
|
|
73
66
|
application's to observe or restore.
|
|
74
67
|
- Automatic classification of which changes form one invariant. See C-2.
|
|
75
68
|
|
|
76
69
|
**Scope.** In space: one machine's projmux installation, the long-lived
|
|
77
|
-
processes it owns, and the
|
|
70
|
+
processes it owns, and the provider sessions its Registry records. In time: from the return
|
|
78
71
|
of one `install` or `update` to the next. **Expiry: a verdict expires when the
|
|
79
72
|
installed binary's SHA changes.** A table printed before an install describes an
|
|
80
73
|
installation that no longer exists.
|
|
@@ -85,7 +78,7 @@ installation that no longer exists.
|
|
|
85
78
|
| --- | --- | --- |
|
|
86
79
|
| `L1` | this reader's own executable link carries the kernel's `(deleted)` suffix | none for the binary. No copy of the replaced image is retained, and the recovery text the install prints on failure is config convergence, never a rollback. Restorability is `not-restorable` on every supported path. |
|
|
87
80
|
| `L2` | the whole-fleet vintage census, the newest `install-residue.jsonl` record whose own census observed anything, and the last `install-replacement.json` pass | end and relaunch the residual process through the routes this application already ships. The drain cutoff bounds the wait, and reaching it changes the row rather than the fleet, so a failed replacement leaves every process exactly where a successful one would have found it. |
|
|
88
|
-
| `L3` |
|
|
81
|
+
| `L3` | the Running-versus-live-session census | there is no projmux-owned generation switch to undo. A `Running` Agent whose provider session is gone is rebound with `projmux agent resume <ref>`, which moves a retired endpoint reference onto the daemon endpoint; a session nothing can confirm has no route this application can establish. |
|
|
89
82
|
|
|
90
83
|
**Enforcement.** `TestDoctorReplacementLayerVerdictsAreFixedByInputCombination`
|
|
91
84
|
fixes every input combination to its two verdicts and its token.
|
|
@@ -93,15 +86,8 @@ fixes every input combination to its two verdicts and its token.
|
|
|
93
86
|
to name the evidence that was missing.
|
|
94
87
|
`TestDoctorReplacementDarwinReportsUnsupportedPlatformForImageAndProcessLayers`
|
|
95
88
|
holds the platform branch.
|
|
96
|
-
`
|
|
97
|
-
holds the `L3`
|
|
98
|
-
`TestDoctorReplacementL3RestorationMovesWhenTheQualificationLaneOpens` holds the
|
|
99
|
-
transition across it. For the `L3` guarantee above,
|
|
100
|
-
`TestActivateManagedCurrentRefusesEveryUnqualifiedRequestBeforeDraining` and
|
|
101
|
-
`TestResumeRefusesAnUnqualifiedPairBeforeAnyHandoverEffect` hold the two doors,
|
|
102
|
-
`TestResumeStillRetiresAVacantGenerationWithoutAReceipt` holds the vacancy
|
|
103
|
-
exception, and `TestQualificationGateRefusesEvidenceCountersNoObservationBacks`
|
|
104
|
-
holds the forgery refusal. For the `L2` guarantee above,
|
|
89
|
+
`TestDoctorReplacementCensusSeparatesRegistryRunningFromLiveProviderSession`
|
|
90
|
+
holds the `L3` census and its mismatch token. For the `L2` guarantee above,
|
|
105
91
|
`TestBrokerRuntimeDrainsWhenItsOwnImageWasReplaced` holds the vintage entry
|
|
106
92
|
condition and that a runtime on the installed image is not drained by it,
|
|
107
93
|
`TestReplacementRolePoliciesMatchTheContractDocument` and
|
|
@@ -250,19 +236,14 @@ the token constants in the code equal, in both directions.
|
|
|
250
236
|
| `L2` | `install-residue-recorded` | `not-replaced` | `restorable` | no live child was observable, and the newest ledger record whose own census observed anything says that install left residue |
|
|
251
237
|
| `L2` | `install-residue-clean` | `replaced` | `restorable` | no live child was observable, and the newest ledger record whose own census observed anything says that install left none |
|
|
252
238
|
| `L2` | `no-observed-processes` | `unknown` | `unknown` | neither the live census nor any ledger record observed anything. Every reading is silent; none says the fleet is clean |
|
|
253
|
-
| `L3` | `
|
|
254
|
-
| `L3` | `registry-running-provider-session-dead` |
|
|
255
|
-
| `L3` | `
|
|
256
|
-
| `L3` | `
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
`pool-derived` means the replacement axis follows the pool rather than the
|
|
263
|
-
token: `replaced` once a generation is draining, handover-pending, or retired —
|
|
264
|
-
because such a generation accepts no new admission, which is exactly the
|
|
265
|
-
sentence C-1's Assumption makes — and `not-replaced` otherwise.
|
|
239
|
+
| `L3` | `registry-unobserved` | `unknown` | `unknown` | no Registry was read, so nothing about the provider sessions was observed |
|
|
240
|
+
| `L3` | `registry-running-provider-session-dead` | `not-replaced` | `not-restorable` | provider evidence contradicts a Registry `Running` Agent |
|
|
241
|
+
| `L3` | `registry-running-session-unobserved` | `not-replaced` | `unknown` | Running Agents rest on the Registry alone, with no provider handle to check |
|
|
242
|
+
| `L3` | `provider-sessions-uncontradicted` | `not-replaced` | `unknown` | the Registry was read and no Running Agent is contradicted or unconfirmed. Nothing contradicts the sessions; nothing establishes a restore route for them either |
|
|
243
|
+
|
|
244
|
+
The `L3` replacement axis is `not-replaced` on every reading that reached the
|
|
245
|
+
Registry: an install replaces no provider session, and this application owns no
|
|
246
|
+
app-server generation switch that could replace one.
|
|
266
247
|
|
|
267
248
|
## Process role vocabulary
|
|
268
249
|
|
|
@@ -423,15 +404,50 @@ absence is stated by this table's `unsupported-platform` row.
|
|
|
423
404
|
|
|
424
405
|
`projmux internal install-replace` runs as a step of `make install`, immediately
|
|
425
406
|
before the residue census so the census measures the fleet the pass left. It
|
|
426
|
-
takes the census, splits the residual processes by disposition,
|
|
427
|
-
published broker
|
|
407
|
+
takes the census, splits the residual processes by disposition, discovers the
|
|
408
|
+
published generation-scoped broker endpoints in this state domain, and dials
|
|
409
|
+
those whose PID hints select this executable's residual processes. PID is only
|
|
410
|
+
a selection hint; the existing ownership and credential checks still authorize
|
|
411
|
+
the connection. The legacy default endpoint key locates the directory and is
|
|
412
|
+
not assumed to be the published runtime. The pass waits a bounded moment and
|
|
428
413
|
writes `install-replacement.json`.
|
|
429
414
|
|
|
415
|
+
A welcome from a current-image runtime cannot stand in for a residual target.
|
|
416
|
+
A drain/closing refusal confirms reachability; if the exact socket disappears
|
|
417
|
+
during a failed request, its disappearance proves that target is already gone. The runtime writes `drain-required`
|
|
418
|
+
before an idle drain closes its connection. Completion follows the original
|
|
419
|
+
socket identities and ownership-checked runtime IDs captured for accepted
|
|
420
|
+
targets, so an absent unrelated socket or a successor published at the same
|
|
421
|
+
path cannot distort the drained count. Runtime IDs distinguish successors even
|
|
422
|
+
when the filesystem reuses the original socket's inode. An unreadable or
|
|
423
|
+
untrusted successor record alone does not prove completion.
|
|
424
|
+
|
|
430
425
|
It **starts nothing** — a replacement pass that launched what it was sent to
|
|
431
426
|
replace would leave more behind than it found, so it dials and never ensures.
|
|
432
|
-
It **signals nothing**: the only request it makes is a socket handshake.
|
|
433
|
-
|
|
434
|
-
|
|
427
|
+
It **signals nothing**: the only request it makes is a socket handshake.
|
|
428
|
+
An unreachable target makes `internal install-replace` exit 1. `make install`
|
|
429
|
+
still runs the residue census, then fails because replacement did not finish.
|
|
430
|
+
The binary publication and config convergence have already completed; this
|
|
431
|
+
failure does not roll them back. Accepted drains that are still carrying work
|
|
432
|
+
remain successful, as do complete, no-target, and unsupported-platform passes.
|
|
433
|
+
Their output is unchanged.
|
|
434
|
+
|
|
435
|
+
On an unreachable result, stderr retains the count and refusal and adds the
|
|
436
|
+
remaining drain targets' role, pid, and mapped executable revision, followed by
|
|
437
|
+
the impact and next action. Targets are rechecked after the refusal; a vanished
|
|
438
|
+
or unreadable target is not invented, and an unavailable build revision is
|
|
439
|
+
`unknown`. These identities are transient terminal output only:
|
|
440
|
+
`install-replacement.json` and the residue ledger retain counts and tokens.
|
|
441
|
+
The replacement record adds `failureStage` on an unsuccessful request:
|
|
442
|
+
`discovery` means target selection, record, or socket validation failed;
|
|
443
|
+
`dial` means the local socket connection failed; `handshake` means the greeting
|
|
444
|
+
or response failed or did not accept a drain. `refusal` keeps its existing broker
|
|
445
|
+
token, when one is available. A current-image welcome has no refusal token.
|
|
446
|
+
Successful, pending, no-target, and unsupported records omit `failureStage`.
|
|
447
|
+
The diagnostic states that later Codex Agents may lack control while the old
|
|
448
|
+
broker remains. Let existing work finish, check that the named processes exit
|
|
449
|
+
naturally, and retry `make install`. If they remain, the operator reviews the
|
|
450
|
+
targets before deciding on termination; the install does not signal them.
|
|
435
451
|
|
|
436
452
|
Its outcome vocabulary is closed, and it reaches the `L2` row as
|
|
437
453
|
`replacement.outcome`:
|
|
@@ -567,13 +583,6 @@ reconstruction.
|
|
|
567
583
|
| `replacement.drained` | `L2` | counter |
|
|
568
584
|
| `replacement.reported` | `L2` | counter |
|
|
569
585
|
| `registry.observed` | `L3` | `true` / `false` |
|
|
570
|
-
| `pool.status` | `L3` | pool status token, or `unobserved` when no pool diagnosis was read |
|
|
571
|
-
| `pool.reason` | `L3` | pool reason token |
|
|
572
|
-
| `pool.action` | `L3` | pool action token |
|
|
573
|
-
| `pool.generations.live` | `L3` | counter |
|
|
574
|
-
| `pool.generations.draining` | `L3` | counter |
|
|
575
|
-
| `qualification.verdict` | `L3` | qualification verdict token |
|
|
576
|
-
| `qualification.reason` | `L3` | qualification reason token |
|
|
577
586
|
| `sessions.running` | `L3` | counter |
|
|
578
587
|
| `sessions.live` | `L3` | counter |
|
|
579
588
|
| `sessions.dead` | `L3` | counter |
|
|
@@ -591,6 +600,5 @@ The replacement policy above is the one thing on this page that acts, and it
|
|
|
591
600
|
acts through a strictly narrower door. `TestReplacementPathEndsNoProcess` holds
|
|
592
601
|
the same guard over the policy table and the install pass: they carry no
|
|
593
602
|
termination, no signalling, and no restart either. **The whole of the action is
|
|
594
|
-
a socket handshake, and the runtime decides.** `L1` atomicity
|
|
595
|
-
|
|
596
|
-
path may alter their behavior.
|
|
603
|
+
a socket handshake, and the runtime decides.** `L1` atomicity is separate work
|
|
604
|
+
on a separate door, and no change on this path may alter its behavior.
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Phase 0 provides the read-only attribution contract consumed by the Resource
|
|
4
4
|
Inspector shipped in Phase 1. `projmux resources`, the client-scoped
|
|
5
5
|
`resource-inspector` popup, the statusbar range, and `Resources:Open` all keep
|
|
6
|
-
the snapshot in memory only for the interactive process lifetime; it
|
|
7
|
-
|
|
6
|
+
the snapshot in memory only for the interactive process lifetime; it is never
|
|
7
|
+
persisted.
|
|
8
8
|
|
|
9
9
|
## Identity and inventory
|
|
10
10
|
|
package/docs/session-restore.md
CHANGED
|
@@ -1,80 +1,39 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Project Startup
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
the existing v1 schema and storage behavior. In snapshot save's runtime id
|
|
6
|
-
duplicate check, a Window or Pane recorded as `MissingRuntime`/`RuntimeUnbound`
|
|
7
|
-
does not claim its retained runtime id, so a tmux id reused after a server
|
|
8
|
-
restart does not refuse the save; two live Windows or two live Panes sharing an
|
|
9
|
-
id are still refused.
|
|
3
|
+
A closed Project starts from its Registry desired state. projmux keeps no other
|
|
4
|
+
saved Project state: the Registry (`registry.json`) is the only input.
|
|
10
5
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
projmux create snapshot
|
|
14
|
-
projmux restore snapshot --session <snapshot-session> [--project <ref> | -p <ref>] --dry-run
|
|
15
|
-
projmux restore snapshot --session <snapshot-session> [--project <ref> | -p <ref>] --yes [--client /dev/pts/N]
|
|
16
|
-
projmux delete snapshot --session <snapshot-session>
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Restore requires an exact snapshot and an exact, closed target Project. The
|
|
20
|
-
dry-run validates both inputs and prints replacement, deletion, preserved-UID,
|
|
21
|
-
and lost-conversation-pointer counts with zero Registry, tmux, and snapshot writes.
|
|
22
|
-
Snapshot Project/Window/Pane metadata is checked against the exact target owner
|
|
23
|
-
chain. A UID held by another root, a cross-kind UID reuse, a Project mismatch,
|
|
24
|
-
or conflicting owner metadata refuses before commit. The ordinary Project-open
|
|
25
|
-
trust authorization must also approve the exact target root before the Registry
|
|
26
|
-
transaction begins.
|
|
27
|
-
|
|
28
|
-
After `--yes`, one atomic Registry transaction replaces only the target
|
|
29
|
-
Project's descendant Window/Pane/Agent graph and its descendant name
|
|
30
|
-
reservations. The Project UID, root, trust metadata, unrelated Projects,
|
|
31
|
-
ControlSessions, and source snapshot bytes are preserved. Metadata-bearing
|
|
32
|
-
snapshots reuse their exact target-subtree UIDs and preserve a surviving
|
|
33
|
-
final-v2 Agent or shell anchor plus a surviving direct default shell.
|
|
34
|
-
Metadata-free legacy snapshots reuse target descendants positionally, select
|
|
35
|
-
the first valid Window-local Pane as the role-agnostic anchor, select the first
|
|
36
|
-
direct shell as the optional default, and mint identities only for missing
|
|
37
|
-
items. An Agent-only Window is valid with an empty default. Repeating the same
|
|
38
|
-
projection is a Registry zero-diff.
|
|
39
|
-
|
|
40
|
-
Resource metadata records the Registry schema that produced it. A v3 snapshot
|
|
41
|
-
is projected through the same root-wide same-kind duplicate-group and
|
|
42
|
-
destination-closure rule as Registry migration: affected resources receive
|
|
43
|
-
their exact UID names, unique names outside the closure are preserved, and no
|
|
44
|
-
numeric suffix is minted. A current-v4 snapshot containing a root-wide
|
|
45
|
-
same-kind collision is rejected as damaged before trust authorization,
|
|
46
|
-
Registry/tmux/provider mutation, or any snapshot write.
|
|
47
|
-
|
|
48
|
-
The committed Registry is then converged by the ordinary Project materializer.
|
|
49
|
-
For a restored offline Agent-anchor Window, snapshot materialization visibly plans a
|
|
50
|
-
lazy default shell, creates the Window from that shell, and stages the Agent on
|
|
51
|
-
its retained anchor Pane UID. A successful repeat writes neither Registry nor
|
|
52
|
-
topology. Snapshot Agent recipes use the canonical provider launch/resume path,
|
|
53
|
-
including their existing fresh-conversation fallback. Stored startup
|
|
54
|
-
commands are not directly executed by snapshot restore. A runtime item refusal
|
|
55
|
-
does not roll the Registry back: desired state and the source snapshot remain
|
|
56
|
-
available for another `Continue project`, and the refusal is reported as an
|
|
57
|
-
item notice. If an explicit client is supplied, the final observable step is
|
|
58
|
-
`switch-client -c` to the Project's declared session even when the background
|
|
59
|
-
continuation has no inherited `TMUX` variable.
|
|
60
|
-
|
|
61
|
-
## Project startup
|
|
62
|
-
|
|
63
|
-
A closed Project has exactly two actions:
|
|
6
|
+
A registered closed Project has exactly two actions. A root that is not a
|
|
7
|
+
registered Project is not asked: it opens fresh, which registers it.
|
|
64
8
|
|
|
65
9
|
- `Continue project` opens the current Registry desired state with the ordinary
|
|
66
10
|
materializer. A retained graph keeps its Project, Window, Pane, and Agent
|
|
67
11
|
UIDs. A zero-Window Project keeps its Project UID and atomically receives one
|
|
68
12
|
new canonical Window and shell UID before materialization.
|
|
69
|
-
- `
|
|
13
|
+
- `Clear layout and open` clears the Project's saved Window and Agent layout
|
|
14
|
+
and opens it again; the folder, its files, `.projmux/config.toml`, and trust
|
|
15
|
+
stay. It atomically replaces the same-root graph with a new Project
|
|
70
16
|
UID and one new canonical Window/shell UID chain, after a confirmation naming
|
|
71
17
|
the exact old Project UID and its Window/Pane/Agent counts. Declining returns
|
|
72
18
|
to the startup rows and writes nothing. It does not archive or retain the old
|
|
73
|
-
generation.
|
|
19
|
+
generation. Its new Window's first Pane follows the saved launch default
|
|
20
|
+
(`tmux-ai-split-mode`), exactly as a Window created from the UI does: the
|
|
21
|
+
choice is made before anything is cleared. The first open of an unregistered
|
|
22
|
+
root, which resolves to the same fresh start, behaves the same.
|
|
74
23
|
|
|
75
24
|
Esc/cancel returns to Projects; it is not an action row. Picker failure falls
|
|
76
25
|
back to the non-destructive `Continue project` action.
|
|
77
26
|
|
|
27
|
+
`Continue project` needs a registered Project. On a root that is not a
|
|
28
|
+
registered Project it refuses with zero Registry writes and points to
|
|
29
|
+
`Clear layout and open` (`continue project unavailable: <root> is not a registered
|
|
30
|
+
Project; choose Clear layout and open`). It never falls back to Fresh on its own.
|
|
31
|
+
|
|
32
|
+
projmux does not save Project state on its own at quit or on a timer.
|
|
33
|
+
`projmux quit` offers only `Quit projmux` and `Cancel`. The hidden `internal tmux autosave-session-state`
|
|
34
|
+
route is kept only so status lines rendered by older installs keep working, and
|
|
35
|
+
it does nothing.
|
|
36
|
+
|
|
78
37
|
Continue resumes an Agent's exact recorded conversation after interrupted,
|
|
79
38
|
killed, abnormal, unknown, or unrecorded termination. Intentional and normal
|
|
80
39
|
termination remain excluded. A recorded receipt must agree on the Agent and
|
|
@@ -87,8 +46,8 @@ A missing, blank, malformed, or mismatched conversation ref, a disabled provider
|
|
|
87
46
|
a missing workspace, or a resume preparation failure skips the Agent with a
|
|
88
47
|
reason. Continue never substitutes a new conversation. Shells and other
|
|
89
48
|
recoverable Agents still converge; an unrecoverable Agent that is itself a
|
|
90
|
-
Window's required anchor keeps the existing Window refusal.
|
|
91
|
-
|
|
49
|
+
Window's required anchor keeps the existing Window refusal. `agent resume`
|
|
50
|
+
retains its separate authority.
|
|
92
51
|
|
|
93
52
|
After Continue commits, its startup summary shows the resumed and skipped Agent
|
|
94
53
|
totals and `projmux diagnostics log --component topology`. The same counts are
|
|
@@ -110,21 +69,28 @@ errors. Dry-run writes no execution event; failed or rolled-back execution
|
|
|
110
69
|
records an error with zero committed counts. Journal and display failures are
|
|
111
70
|
best effort and never change the topology result.
|
|
112
71
|
|
|
113
|
-
`
|
|
114
|
-
preserves the root, Git/worktrees, trust decision, and all unrelated Registry
|
|
72
|
+
`Clear layout and open` preserves the root, Git/worktrees, trust decision, and all unrelated Registry
|
|
115
73
|
graphs while changing the Project identity. A rejected commit retains the
|
|
116
|
-
exact old Registry preimage. Repeating `
|
|
74
|
+
exact old Registry preimage. Repeating `Clear layout and open` replaces identity again;
|
|
117
75
|
each successful result has exactly one Project claiming the root.
|
|
118
76
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
the
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
77
|
+
The saved launch default is used only when the open carries the exact client
|
|
78
|
+
that pressed the row. The order is:
|
|
79
|
+
|
|
80
|
+
1. Ask. A picker mode (`selective`, the unset default, or `resume`) opens its
|
|
81
|
+
picker on the Pane the row was pressed in, before the old layout is cleared
|
|
82
|
+
or the new Session exists; a provider mode and `shell` are already the
|
|
83
|
+
answer and open nothing.
|
|
84
|
+
2. Clear the layout and create the new Session with its one shell Pane.
|
|
85
|
+
3. Fill it: an Agent answer is created in that Window first, and the shell is
|
|
86
|
+
then removed through the canonical Pane delete.
|
|
87
|
+
4. Move the pressing client onto the finished Session.
|
|
88
|
+
|
|
89
|
+
The client therefore never sees a shell Pane that is about to be replaced.
|
|
90
|
+
Closing the picker without a choice does not stop the open: the Session opens
|
|
91
|
+
with its shell Pane and nothing is said. An open without the exact client -- a
|
|
92
|
+
detached `start project`, a scripted open -- asks nothing, in every mode, and
|
|
93
|
+
keeps the plain shell Pane. A question that cannot be asked, or an answer that
|
|
94
|
+
cannot be filled in, costs one line on that client after the move and keeps the
|
|
95
|
+
shell Pane; the Project stays open either way. `Continue project` and the
|
|
96
|
+
`start project`/`open project` verbs never use the saved launch default.
|