instar 1.3.511 → 1.3.512
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +67 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +24 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/CoherenceJournal.d.ts +31 -1
- package/dist/core/CoherenceJournal.d.ts.map +1 -1
- package/dist/core/CoherenceJournal.js +49 -2
- package/dist/core/CoherenceJournal.js.map +1 -1
- package/dist/core/JournalSyncApplier.d.ts.map +1 -1
- package/dist/core/JournalSyncApplier.js +18 -0
- package/dist/core/JournalSyncApplier.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +44 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +5 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/types.d.ts +27 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/GreenPrAutoMerger.d.ts +188 -0
- package/dist/monitoring/GreenPrAutoMerger.d.ts.map +1 -0
- package/dist/monitoring/GreenPrAutoMerger.js +393 -0
- package/dist/monitoring/GreenPrAutoMerger.js.map +1 -0
- package/dist/monitoring/GuardLatchStore.d.ts +134 -0
- package/dist/monitoring/GuardLatchStore.d.ts.map +1 -0
- package/dist/monitoring/GuardLatchStore.js +255 -0
- package/dist/monitoring/GuardLatchStore.js.map +1 -0
- package/dist/monitoring/MergeRunner.d.ts +126 -0
- package/dist/monitoring/MergeRunner.d.ts.map +1 -0
- package/dist/monitoring/MergeRunner.js +296 -0
- package/dist/monitoring/MergeRunner.js.map +1 -0
- package/dist/monitoring/floorDriftCanary.d.ts +88 -0
- package/dist/monitoring/floorDriftCanary.d.ts.map +1 -0
- package/dist/monitoring/floorDriftCanary.js +89 -0
- package/dist/monitoring/floorDriftCanary.js.map +1 -0
- package/dist/monitoring/greenPrAutomergeWiring.d.ts +73 -0
- package/dist/monitoring/greenPrAutomergeWiring.d.ts.map +1 -0
- package/dist/monitoring/greenPrAutomergeWiring.js +273 -0
- package/dist/monitoring/greenPrAutomergeWiring.js.map +1 -0
- package/dist/monitoring/greenPrLogic.d.ts +121 -0
- package/dist/monitoring/greenPrLogic.d.ts.map +1 -0
- package/dist/monitoring/greenPrLogic.js +198 -0
- package/dist/monitoring/greenPrLogic.js.map +1 -0
- package/dist/monitoring/guardManifest.d.ts.map +1 -1
- package/dist/monitoring/guardManifest.js +12 -0
- package/dist/monitoring/guardManifest.js.map +1 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +2 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +16 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +5 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +112 -1
- package/dist/server/routes.js.map +1 -1
- package/dist/server/stopGate.d.ts +45 -0
- package/dist/server/stopGate.d.ts.map +1 -1
- package/dist/server/stopGate.js +74 -0
- package/dist/server/stopGate.js.map +1 -1
- package/package.json +1 -1
- package/scripts/safe-merge.mjs +449 -59
- package/src/data/builtin-manifest.json +64 -64
- package/upgrades/1.3.512.md +65 -0
- package/upgrades/side-effects/green-pr-automerge-enforcement.md +171 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Side-Effects Review — Green-PR Auto-Merge Enforcement (Phase 7 becomes machinery)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `green-pr-automerge-enforcement`
|
|
4
|
+
**Date:** `2026-06-12`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `green-pr-automerge-secondpass subagent (high-risk: merge authority + gate + watcher)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
A background watcher (`GreenPrAutoMerger`) that merges a green, mergeable, non-held PR
|
|
11
|
+
this agent authored — so the merge survives session death (the prose "Phase 7" rule died
|
|
12
|
+
with the session that read it; this is machinery). It rides on a hardened
|
|
13
|
+
`scripts/safe-merge.mjs` (the act-time re-verifier), a pool-visible kill-switch
|
|
14
|
+
(`GuardLatchStore` on a new replicated `guard-latch` coherence-journal kind), a per-PR
|
|
15
|
+
failure ladder + circuit breaker, an identity contract, a floor-drift canary, and a Layer-2
|
|
16
|
+
session-exit nudge. Off fleet-wide (`DARK_GATE_EXCLUSIONS: deliberate-fleet-default`),
|
|
17
|
+
flipped on per dev agent with `expectedGhLogin`, repo-gated to an instar checkout with
|
|
18
|
+
`scripts/safe-merge.mjs` present. Spec: `docs/specs/green-pr-automerge-enforcement.md`
|
|
19
|
+
(converged round 7, approved). New modules: `src/monitoring/{GreenPrAutoMerger,MergeRunner,
|
|
20
|
+
GuardLatchStore,greenPrLogic,floorDriftCanary,greenPrAutomergeWiring}.ts`; `guard-latch` kind
|
|
21
|
+
in `CoherenceJournal.ts` + `JournalSyncApplier.ts`; Layer-2 helpers in `stopGate.ts`; six
|
|
22
|
+
routes in `routes.ts`; boot wiring in `commands/server.ts`; config/registry/migration in
|
|
23
|
+
`ConfigDefaults.ts`, `devGatedFeatures.ts`, `guardManifest.ts`, `PostUpdateMigrator.ts`,
|
|
24
|
+
`types.ts`.
|
|
25
|
+
|
|
26
|
+
## Decision-point inventory
|
|
27
|
+
|
|
28
|
+
- `GreenPrAutoMerger.tick` candidate gate — **add** — decides which PRs are merge-eligible
|
|
29
|
+
(namespace + hold + mergeable + settled-green + protected-paths). Fail-toward-skip.
|
|
30
|
+
- `GuardLatchStore.isMergeAllowed` (dual-latch gate) — **add** — rollback + emergency-pause
|
|
31
|
+
must BOTH be open; unreadable peers → arrive-disabled.
|
|
32
|
+
- `safe-merge` required-contexts cross-check — **add** — producer-bound floor; refuses on any
|
|
33
|
+
unverifiable/missing/wrong-producer context.
|
|
34
|
+
- Layer-2 `greenPrBlock` (stop-gate hot path) — **add** — blocks a session ending with a
|
|
35
|
+
green unmerged PR on its branch, ONCE, mode-independently. No runnable command in any variant.
|
|
36
|
+
- The existing stop-gate router hook — **modify** — gains a mode-independent greenPrBlock
|
|
37
|
+
branch before the `mode === 'off'` early return (always-overwritten by migrateHooks).
|
|
38
|
+
|
|
39
|
+
## Over-block — legitimate inputs this rejects that it shouldn't
|
|
40
|
+
|
|
41
|
+
- A genuinely-green PR whose required-contexts cannot be FETCHED (gh/API hiccup) is refused
|
|
42
|
+
(`refused:contexts-unverifiable`) rather than merged. Intended: fail-toward-skip. The PR
|
|
43
|
+
stays open; the next tick retries; the hold-age backstop surfaces it if it rots.
|
|
44
|
+
- A PR whose CI floor was renamed out-of-band is refused until the floor-drift canary names
|
|
45
|
+
the drift. Intended over-block (a drifted floor must not be merged around).
|
|
46
|
+
- A PR touching protected paths is never auto-merged even when green — routed to the operator.
|
|
47
|
+
Intended (those PRs can mint hollow floor contexts; human eyes required).
|
|
48
|
+
|
|
49
|
+
## Under-block — failure modes this still misses
|
|
50
|
+
|
|
51
|
+
- **Stale-base merges (Decision 9, ratified):** `--admin` bypasses the up-to-date-branch
|
|
52
|
+
requirement, so a PR tested against an older `main` can merge an untested integration.
|
|
53
|
+
Bounded: textual conflicts never merge (`mergeable == MERGEABLE`), `main` re-runs full CI
|
|
54
|
+
after every merge (Zero-Failure makes breakage owned + the audit names the merge), and this
|
|
55
|
+
relocates the EXISTING manual-merge residual unchanged. A strict-base-freshness mode is on
|
|
56
|
+
the fleet-promotion checklist.
|
|
57
|
+
- **Branch namespace is a filter, not provenance (Decision 8):** anyone holding the shared gh
|
|
58
|
+
credential can name a branch `echo/…`; the floor's producer-bound CI contexts are what make
|
|
59
|
+
a candidate "pre-approved by construction."
|
|
60
|
+
- **Multi-machine peer-latch READ is single-machine in this PR:** `readPeerLatches: () => []`.
|
|
61
|
+
Outbound replication (the journal emit) works; the merged peer READ surface is a follow-up.
|
|
62
|
+
Honest consequence: on a multi-machine pool a rollback set on machine A replicates outbound
|
|
63
|
+
but machine B does not yet MERGE A's latch into its gate. The durable local file is the
|
|
64
|
+
authoritative gate per-machine, and the lease serializes the ACT — so two machines never
|
|
65
|
+
both merge — but a cross-machine STOP is not yet honored on the non-originating holder. This
|
|
66
|
+
is disclosed; the dev agent runs effectively single-machine for merge authority today.
|
|
67
|
+
|
|
68
|
+
## Level-of-abstraction fit
|
|
69
|
+
|
|
70
|
+
Correct layer: a monitoring watcher (the ReleaseReadinessSentinel precedent) that drives the
|
|
71
|
+
blessed `safe-merge` wrapper. The watcher holds NO independent merge path and never trusts
|
|
72
|
+
safe-merge's exit code (independent `gh pr view` confirm, B10). The kill-switch rides the
|
|
73
|
+
existing coherence-journal replication + fenced lease (no new distributed primitive).
|
|
74
|
+
|
|
75
|
+
## Signal vs authority compliance
|
|
76
|
+
|
|
77
|
+
The watcher is Tier-0: the ONLY discretionary classification is hold/candidate status, and its
|
|
78
|
+
failure direction is fail-toward-skip (audited), never fail-toward-merge. Everything that
|
|
79
|
+
decides "is this change good" already happened upstream (spec process + gates + CI); safe-merge
|
|
80
|
+
re-verifies at act time. The Layer-2 `greenPrBlock` blocks ONCE on objective replicated state
|
|
81
|
+
(green candidate + exact branch match + staleness gate + armed gate) and fails open on every
|
|
82
|
+
error — it does not repeat the brittle-substring-with-blocking-authority pattern of the
|
|
83
|
+
stated-continuation guard it sits beside (that foundation tension is recorded in the spec, not
|
|
84
|
+
inherited).
|
|
85
|
+
|
|
86
|
+
## Interactions
|
|
87
|
+
|
|
88
|
+
- Shares the stop-gate hot-path response with the UnjustifiedStopGate; greenPrBlock is computed
|
|
89
|
+
LAZILY (only when the snapshot has candidates) and is mode-independent, so it does not depend
|
|
90
|
+
on the UnjustifiedStopGate mode (which ships `off`).
|
|
91
|
+
- Adds a journal kind: the `guard-latch` kind is closed-schema in both the writer
|
|
92
|
+
(`CoherenceJournal`) and the receiver (`JournalSyncApplier`) — a peer's forged guard-latch
|
|
93
|
+
entry is schema-rejected like any other kind.
|
|
94
|
+
- One aggregated attention item with a machine-stable id (`green-pr-automerge:aggregate`) — does
|
|
95
|
+
NOT create per-PR topics (the notification-flood burst-invariant bound).
|
|
96
|
+
|
|
97
|
+
## External surfaces
|
|
98
|
+
|
|
99
|
+
- Merges PRs on GitHub (the one durable external side-effect — ratified at the approval gate;
|
|
100
|
+
the operator-token admin merge already happened manually via the same script since June 9).
|
|
101
|
+
- Six new HTTP routes (`/green-pr-automerge*`); `/enable` + `/pool-disarm` are dashboard-PIN
|
|
102
|
+
gated (operator authority), `/rollback` + `/hold` + `/tick` are Bearer.
|
|
103
|
+
- Reporter hook payload gains `cwd` (always-overwritten template; free fleet-wide).
|
|
104
|
+
|
|
105
|
+
## Multi-machine posture (Cross-Machine Coherence)
|
|
106
|
+
|
|
107
|
+
| Surface | Posture | Why |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `state/green-pr-automerge.json` | machine-local BY DESIGN | attempt ledger; the ACT is lease-serialized |
|
|
110
|
+
| `state/green-pr-automerge-latches.json` | machine-local authoritative + journal-replicated | durable STOP survives restart; emit replicates outbound |
|
|
111
|
+
| `guard-latch` journal kind | pool-replicated (outbound) | a STOP/marker propagates to peers |
|
|
112
|
+
| peer-latch READ (merged gate) | single-machine in this PR (follow-up) | disclosed under-block above |
|
|
113
|
+
| Layer-2 snapshot | machine-local (holder only) | sessions on a non-holder get no belt; Layer 1 on the holder is the guarantee |
|
|
114
|
+
| Aggregated attention id | machine-stable | lease makes dual-raise impractical; stable id makes it harmless |
|
|
115
|
+
|
|
116
|
+
## Rollback cost
|
|
117
|
+
|
|
118
|
+
- Runtime: `POST /green-pr-automerge/rollback` (Bearer, anyone can STOP) disarms instantly;
|
|
119
|
+
`dryRun: true` and `enabled: false` are config levers. Fleet default is off regardless.
|
|
120
|
+
- Code: revert the PR. No data migration — the new state files are additive and machine-local;
|
|
121
|
+
the new `guard-latch` journal kind is additive (readers ignore unknown kinds). The hook
|
|
122
|
+
template changes are always-overwritten, so a revert restores the prior templates on the next
|
|
123
|
+
migration.
|
|
124
|
+
|
|
125
|
+
## Tests
|
|
126
|
+
|
|
127
|
+
- Unit (123 new): safe-merge hardening (27), guard-latch store (13), pure logic (31),
|
|
128
|
+
orchestrator (14), merge runner (12), floor-drift (9), Layer-2 helpers (11), + the journal
|
|
129
|
+
suites pass with the new kind (35).
|
|
130
|
+
- Integration (6): the routes over the real HTTP pipeline — 503 unwired → 200 wired
|
|
131
|
+
(feature-alive), rollback gate closing, PIN gating, the warm-up→merge tick flow.
|
|
132
|
+
- Honest gap vs the spec's full test list: a real-AgentServer-boot E2E and a dedicated
|
|
133
|
+
chaos-interleaving integration test are NOT in this PR — the route-level integration proves
|
|
134
|
+
the feature is alive through the real `createRoutes` pipeline, and the restart/orphan and
|
|
135
|
+
latch-partition paths are covered at the unit tier (MergeRunner orphan reap; GuardLatchStore
|
|
136
|
+
absorbing/unreadable). Flagged for a follow-up E2E hardening pass.
|
|
137
|
+
|
|
138
|
+
## Second-pass review
|
|
139
|
+
|
|
140
|
+
**Verdict: CONCUR.** An independent reviewer audited the artifact against the code (safe-merge,
|
|
141
|
+
GreenPrAutoMerger, GuardLatchStore, MergeRunner, stopGate, the boot wiring), adversarially
|
|
142
|
+
hunting for a path to an unintended merge. Findings:
|
|
143
|
+
- No path to an unintended merge. The act path is gated in strict order every tick
|
|
144
|
+
(lease → single-flight → dual-latch gate → breaker → warm-up → candidate → identity →
|
|
145
|
+
contract probe → live re-fetch → spawn); safe-merge is the independent act-time authority and
|
|
146
|
+
refuses on red/missing-e2e/wrong-producer-floor/head-moved/unverifiable. The empty-rollup edge
|
|
147
|
+
(`statusCheckRollup:[]` passing the cheap list filter) is caught and refused at act time by
|
|
148
|
+
safe-merge — the non-authoritative filter never causes a merge.
|
|
149
|
+
- Fail direction is fail-toward-SKIP on every traced path (candidate, protected-paths-unverifiable,
|
|
150
|
+
identity unconfigured/unresolved/mismatch, gather/runner exceptions, every safe-merge error exit).
|
|
151
|
+
- Identity contract enforced before acting (default `expectedGhLogin:''` → skip every act).
|
|
152
|
+
- Dual-latch read every tick; unreadable peers arrive-disabled; rollback Bearer, re-arm PIN-gated.
|
|
153
|
+
- B10 independent confirmation at both safe-merge and the watcher.
|
|
154
|
+
- Layer-2 is signal-not-authority, fails open, no variant emits a runnable command.
|
|
155
|
+
- Wiring integrity confirmed (repo-gate → 503; real deps; same latch instance backs act + Layer 2).
|
|
156
|
+
- Two non-blocking observations, both fail-safe: the Layer-2 hot path hardcoded `tickIntervalMs`
|
|
157
|
+
(FIXED — now read from config) and a rollback landing mid-spawned-attempt does not abort that one
|
|
158
|
+
bounded attempt (disclosed; lease + single-flight bound it to one).
|
|
159
|
+
|
|
160
|
+
## CI hardening (registry + ratchet parity)
|
|
161
|
+
|
|
162
|
+
Full-suite triage surfaced four registry/parity gates, all addressed: the new `guard-latch`
|
|
163
|
+
journal kind updated the `CoherenceJournal.getOwnAdvert` test enumeration; the six routes were
|
|
164
|
+
registered in `CapabilityIndex` (`/capabilities` discoverability); the migrator CLAUDE.md section
|
|
165
|
+
was tracked in the feature-delivery-completeness parity test (migrator-only, like Release
|
|
166
|
+
Readiness); and the ~20 new fail-toward-skip `catch` blocks were annotated `@silent-fallback-ok`
|
|
167
|
+
(with the dead `isFile` probe in `resolveBranchFromCwd` removed) so the no-silent-fallbacks ratchet
|
|
168
|
+
stays at its baseline. Three other full-suite reds were confirmed NOT from this change
|
|
169
|
+
(sharedStateRoutes passes in isolation — cross-talk; sign-instar-lockfile + the npm-pack
|
|
170
|
+
packageTemplateShape fail on local signing-key / `proper-lockfile` resolution; two e2e narratives
|
|
171
|
+
are pre-existing). CI's clean room is the authority.
|