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.
Files changed (69) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +67 -1
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +24 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/CoherenceJournal.d.ts +31 -1
  8. package/dist/core/CoherenceJournal.d.ts.map +1 -1
  9. package/dist/core/CoherenceJournal.js +49 -2
  10. package/dist/core/CoherenceJournal.js.map +1 -1
  11. package/dist/core/JournalSyncApplier.d.ts.map +1 -1
  12. package/dist/core/JournalSyncApplier.js +18 -0
  13. package/dist/core/JournalSyncApplier.js.map +1 -1
  14. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  15. package/dist/core/PostUpdateMigrator.js +44 -0
  16. package/dist/core/PostUpdateMigrator.js.map +1 -1
  17. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  18. package/dist/core/devGatedFeatures.js +5 -0
  19. package/dist/core/devGatedFeatures.js.map +1 -1
  20. package/dist/core/types.d.ts +27 -0
  21. package/dist/core/types.d.ts.map +1 -1
  22. package/dist/core/types.js.map +1 -1
  23. package/dist/monitoring/GreenPrAutoMerger.d.ts +188 -0
  24. package/dist/monitoring/GreenPrAutoMerger.d.ts.map +1 -0
  25. package/dist/monitoring/GreenPrAutoMerger.js +393 -0
  26. package/dist/monitoring/GreenPrAutoMerger.js.map +1 -0
  27. package/dist/monitoring/GuardLatchStore.d.ts +134 -0
  28. package/dist/monitoring/GuardLatchStore.d.ts.map +1 -0
  29. package/dist/monitoring/GuardLatchStore.js +255 -0
  30. package/dist/monitoring/GuardLatchStore.js.map +1 -0
  31. package/dist/monitoring/MergeRunner.d.ts +126 -0
  32. package/dist/monitoring/MergeRunner.d.ts.map +1 -0
  33. package/dist/monitoring/MergeRunner.js +296 -0
  34. package/dist/monitoring/MergeRunner.js.map +1 -0
  35. package/dist/monitoring/floorDriftCanary.d.ts +88 -0
  36. package/dist/monitoring/floorDriftCanary.d.ts.map +1 -0
  37. package/dist/monitoring/floorDriftCanary.js +89 -0
  38. package/dist/monitoring/floorDriftCanary.js.map +1 -0
  39. package/dist/monitoring/greenPrAutomergeWiring.d.ts +73 -0
  40. package/dist/monitoring/greenPrAutomergeWiring.d.ts.map +1 -0
  41. package/dist/monitoring/greenPrAutomergeWiring.js +273 -0
  42. package/dist/monitoring/greenPrAutomergeWiring.js.map +1 -0
  43. package/dist/monitoring/greenPrLogic.d.ts +121 -0
  44. package/dist/monitoring/greenPrLogic.d.ts.map +1 -0
  45. package/dist/monitoring/greenPrLogic.js +198 -0
  46. package/dist/monitoring/greenPrLogic.js.map +1 -0
  47. package/dist/monitoring/guardManifest.d.ts.map +1 -1
  48. package/dist/monitoring/guardManifest.js +12 -0
  49. package/dist/monitoring/guardManifest.js.map +1 -1
  50. package/dist/server/AgentServer.d.ts +2 -0
  51. package/dist/server/AgentServer.d.ts.map +1 -1
  52. package/dist/server/AgentServer.js +2 -0
  53. package/dist/server/AgentServer.js.map +1 -1
  54. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  55. package/dist/server/CapabilityIndex.js +16 -0
  56. package/dist/server/CapabilityIndex.js.map +1 -1
  57. package/dist/server/routes.d.ts +5 -0
  58. package/dist/server/routes.d.ts.map +1 -1
  59. package/dist/server/routes.js +112 -1
  60. package/dist/server/routes.js.map +1 -1
  61. package/dist/server/stopGate.d.ts +45 -0
  62. package/dist/server/stopGate.d.ts.map +1 -1
  63. package/dist/server/stopGate.js +74 -0
  64. package/dist/server/stopGate.js.map +1 -1
  65. package/package.json +1 -1
  66. package/scripts/safe-merge.mjs +449 -59
  67. package/src/data/builtin-manifest.json +64 -64
  68. package/upgrades/1.3.512.md +65 -0
  69. 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.