Commit e9b10a1
committed
fix(plugin-self-update): persist survives_respawn through install + heal stale manifests
Plugin authors who set `[capabilities].survives_respawn = true` in their
source plugin.toml saw the bit silently dropped on `garyx plugins install`
— `synthesize_manifest_toml` rendered five capability fields and didn't
emit this one, so the regenerated plugin.toml always defaulted false.
The host's `request_self_replace` handler reads the flag off the on-disk
manifest and refuses every swap with `reason=no_survives_respawn` when
false, stranding opted-in plugins at whatever version was first
installed: every subsequent self-update tick called the RPC, the host
refused, and the install fell back to "no upgrade" silently for as long
as the bit kept disappearing on every install.
Two coordinated changes:
1. **Fix the renderer.** `CapabilitiesResponse` gains a `survives_respawn`
field (serde default false). `synthesize_manifest_toml` threads it
into the generated `[capabilities]` block, so fresh installs of any
plugin that advertises the bit in its `describe` response get it
persisted correctly. The preflight drift comment notes why
`survives_respawn` stays out of the capability mismatch check — it's
operator opt-in intent rather than intrinsic binary behavior, and a
hand-edited disk value may legitimately differ from `describe`.
2. **Heal stale on-disk manifests.** Existing installs synthesized by
older garyx still have the field missing; without help they'd need a
manual `garyx plugins install --force` to recover. The host now
self-heals at startup: after preflight, if `describe` reports
`survives_respawn = true` and the on-disk manifest is missing the
field, the `[capabilities]` block is patched in place (atomic write
via PID + atomic-counter + nanosecond temp name + O_EXCL +
sync_all + rename). An explicit `survives_respawn = false` is left
alone — operator opt-out is preserved.
The in-memory manifest is mutated to match before the manager
builds its snapshot, so the first `request_self_replace` this
session accepts (no need to wait for next gateway restart).
Edits scoped to `[capabilities]` to avoid false positives on stray
comments mentioning the field name elsewhere. Section boundary
detection only treats subsequent `[...]` headers as end-of-table —
TOML blank lines do not end a table, so an explicit
`survives_respawn = false` after a blank inside `[capabilities]` is
still detected as opt-out (and the file is left byte-identical).
Tests: 7 backfill unit tests (missing-field write, byte-identical
opt-out, no-section error, trailing-section EOF terminator, scoped
detection ignores comments outside the block, blank-line-then-opt-out
correctness, 4-thread same-file contention lands a single writer
with no duplicate key); 1 round-trip regression test pinning the
synthesize emission contract.1 parent 9582915 commit e9b10a1
9 files changed
Lines changed: 477 additions & 10 deletions
File tree
- garyx-channels/src
- dispatcher
- plugin_host
- inspect
- sender
- subprocess_plugin
- garyx/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
979 | 979 | | |
980 | 980 | | |
981 | 981 | | |
| 982 | + | |
982 | 983 | | |
983 | 984 | | |
984 | 985 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
| 27 | + | |
25 | 28 | | |
26 | 29 | | |
27 | 30 | | |
| |||
294 | 297 | | |
295 | 298 | | |
296 | 299 | | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
297 | 304 | | |
298 | 305 | | |
299 | 306 | | |
| |||
430 | 437 | | |
431 | 438 | | |
432 | 439 | | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
433 | 593 | | |
434 | 594 | | |
435 | 595 | | |
| |||
0 commit comments