reanimator 0.1.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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +207 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +483 -0
  5. data/SECURITY.md +32 -0
  6. data/exe/reanimator +6 -0
  7. data/lib/reanimator/acceptance_criterion.rb +75 -0
  8. data/lib/reanimator/agent_connection.rb +62 -0
  9. data/lib/reanimator/agent_profile.rb +51 -0
  10. data/lib/reanimator/agents/adapter.rb +49 -0
  11. data/lib/reanimator/agents/capability.rb +29 -0
  12. data/lib/reanimator/agents/constraints.rb +57 -0
  13. data/lib/reanimator/agents/hosted.rb +38 -0
  14. data/lib/reanimator/agents/local.rb +46 -0
  15. data/lib/reanimator/agents/patch.rb +60 -0
  16. data/lib/reanimator/agents/repair_task.rb +51 -0
  17. data/lib/reanimator/agents/result.rb +42 -0
  18. data/lib/reanimator/agents/strategies/arithmetic_fix.rb +51 -0
  19. data/lib/reanimator/agents/strategies/base.rb +26 -0
  20. data/lib/reanimator/agents.rb +38 -0
  21. data/lib/reanimator/autonomy_level.rb +41 -0
  22. data/lib/reanimator/baseline.rb +106 -0
  23. data/lib/reanimator/baseline_runner.rb +81 -0
  24. data/lib/reanimator/bounded_command.rb +87 -0
  25. data/lib/reanimator/classifier.rb +89 -0
  26. data/lib/reanimator/cli.rb +273 -0
  27. data/lib/reanimator/cohort.rb +61 -0
  28. data/lib/reanimator/commissioning/fixture.rb +69 -0
  29. data/lib/reanimator/commissioning/report.rb +45 -0
  30. data/lib/reanimator/commissioning/test.rb +145 -0
  31. data/lib/reanimator/confidence.rb +66 -0
  32. data/lib/reanimator/configuration.rb +35 -0
  33. data/lib/reanimator/contract_file.rb +116 -0
  34. data/lib/reanimator/contract_snapshot.rb +188 -0
  35. data/lib/reanimator/criteria_stack.rb +91 -0
  36. data/lib/reanimator/criterion_result.rb +70 -0
  37. data/lib/reanimator/detectors/base.rb +49 -0
  38. data/lib/reanimator/detectors/bundler.rb +68 -0
  39. data/lib/reanimator/detectors/commands.rb +112 -0
  40. data/lib/reanimator/detectors/fork.rb +25 -0
  41. data/lib/reanimator/detectors/github_actions.rb +68 -0
  42. data/lib/reanimator/detectors/operational_proof.rb +48 -0
  43. data/lib/reanimator/detectors/rails_app.rb +51 -0
  44. data/lib/reanimator/detectors/relationships.rb +46 -0
  45. data/lib/reanimator/detectors/ruby_gem.rb +40 -0
  46. data/lib/reanimator/detectors/security_controls.rb +36 -0
  47. data/lib/reanimator/discovered_fact.rb +99 -0
  48. data/lib/reanimator/discovery.rb +48 -0
  49. data/lib/reanimator/discovery_result.rb +89 -0
  50. data/lib/reanimator/drift_detector.rb +227 -0
  51. data/lib/reanimator/drift_report.rb +86 -0
  52. data/lib/reanimator/effective_contract.rb +108 -0
  53. data/lib/reanimator/effective_policy_resolver.rb +116 -0
  54. data/lib/reanimator/errors.rb +21 -0
  55. data/lib/reanimator/evaluators/base.rb +55 -0
  56. data/lib/reanimator/evaluators/command.rb +34 -0
  57. data/lib/reanimator/evaluators/documentation_check.rb +25 -0
  58. data/lib/reanimator/evaluators/http_smoke.rb +19 -0
  59. data/lib/reanimator/evaluators/repository_integrity.rb +22 -0
  60. data/lib/reanimator/evaluators/security_evidence.rb +24 -0
  61. data/lib/reanimator/evaluators/support_matrix.rb +25 -0
  62. data/lib/reanimator/evaluators.rb +41 -0
  63. data/lib/reanimator/family/gate.rb +40 -0
  64. data/lib/reanimator/family/gate_result.rb +46 -0
  65. data/lib/reanimator/family/gate_runner.rb +91 -0
  66. data/lib/reanimator/family.rb +89 -0
  67. data/lib/reanimator/family_inference.rb +113 -0
  68. data/lib/reanimator/git.rb +72 -0
  69. data/lib/reanimator/isolation.rb +36 -0
  70. data/lib/reanimator/language_inference.rb +43 -0
  71. data/lib/reanimator/lifecycle_intent.rb +93 -0
  72. data/lib/reanimator/obligation.rb +35 -0
  73. data/lib/reanimator/permission_model.rb +61 -0
  74. data/lib/reanimator/portfolio.rb +68 -0
  75. data/lib/reanimator/portfolio_drift.rb +120 -0
  76. data/lib/reanimator/profile_inference.rb +37 -0
  77. data/lib/reanimator/profiles.rb +110 -0
  78. data/lib/reanimator/proof_of_life.rb +45 -0
  79. data/lib/reanimator/proposed_change.rb +55 -0
  80. data/lib/reanimator/provenance.rb +39 -0
  81. data/lib/reanimator/relationship.rb +62 -0
  82. data/lib/reanimator/repair_run.rb +146 -0
  83. data/lib/reanimator/reports/agents.rb +28 -0
  84. data/lib/reanimator/reports/baseline.rb +73 -0
  85. data/lib/reanimator/reports/commissioning.rb +48 -0
  86. data/lib/reanimator/reports/contract.rb +70 -0
  87. data/lib/reanimator/reports/discovery.rb +38 -0
  88. data/lib/reanimator/reports/drift.rb +63 -0
  89. data/lib/reanimator/reports/families.rb +41 -0
  90. data/lib/reanimator/reports/family_gates.rb +41 -0
  91. data/lib/reanimator/reports/github_check.rb +45 -0
  92. data/lib/reanimator/reports/inventory.rb +37 -0
  93. data/lib/reanimator/reports/permissions.rb +32 -0
  94. data/lib/reanimator/reports/portfolio_baseline.rb +68 -0
  95. data/lib/reanimator/reports/portfolio_drift.rb +107 -0
  96. data/lib/reanimator/reports/run.rb +52 -0
  97. data/lib/reanimator/reports/snapshot.rb +58 -0
  98. data/lib/reanimator/reports.rb +36 -0
  99. data/lib/reanimator/repository.rb +96 -0
  100. data/lib/reanimator/repository_metadata.rb +78 -0
  101. data/lib/reanimator/repository_state.rb +48 -0
  102. data/lib/reanimator/routing/decision.rb +35 -0
  103. data/lib/reanimator/routing/router.rb +122 -0
  104. data/lib/reanimator/run.rb +48 -0
  105. data/lib/reanimator/safety_floor.rb +81 -0
  106. data/lib/reanimator/security_control.rb +87 -0
  107. data/lib/reanimator/security_posture.rb +80 -0
  108. data/lib/reanimator/snapshot_store.rb +78 -0
  109. data/lib/reanimator/task_class.rb +63 -0
  110. data/lib/reanimator/version.rb +5 -0
  111. data/lib/reanimator/vitality_profile.rb +44 -0
  112. data/lib/reanimator/waiver.rb +74 -0
  113. data/lib/reanimator.rb +214 -0
  114. metadata +262 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f927dd25aecfa803bedb5db2e7c79577d7518f0ccb8eb2cc040469d579c61bcd
4
+ data.tar.gz: d0b15db4335ffa7c90ea2435b627ffd82096f15b631b448ad185b634ad8a7e56
5
+ SHA512:
6
+ metadata.gz: 883d2e3cedb4ffb3df2cddb11b41a79f8becc3f7a9288ea9399cc7f23729fed44f608886bed08858353a9b2b67f1c8a0386e2e92bab23c13b39cdd66d88d2b34
7
+ data.tar.gz: 6e0b56fa0c9bfd718dff86225d233153a289996226912a112015f11f6f0253e67544c67b2be0781ccb6cdb4e1773848e251ba3b88e85a5606297f4ef27a06c90
data/CHANGELOG.md ADDED
@@ -0,0 +1,207 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-10-28
10
+
11
+ ### Changed
12
+
13
+ - **The product is now Reanimator** (ADR-006). The gem name `frankenstein` is
14
+ held on RubyGems by an actively downloaded Prometheus library, so 0.1.0 could
15
+ not ship under it — but the better reason is that Frankenstein names a single
16
+ dramatic act of revival, and this tool does something else: it proves,
17
+ continuously and read-only, that a repository has not quietly rotted. Gem
18
+ `reanimator`, module `Reanimator`, command `reanimator`, contract file
19
+ `.reanimator.yml`, snapshot file `.reanimator-snapshot.json`, environment
20
+ variables `REANIMATOR_*`. Nothing is published yet, so no existing
21
+ installation or contract file is affected.
22
+
23
+ ### Added
24
+
25
+ - Security posture enforcement (section 12). The posture was a label; it is now
26
+ a decision with consequences. `SecurityControl` registers the controls a
27
+ posture can require - dependency review, secret scanning, static analysis,
28
+ security policy, ownership - each named by **obligation rather than tool**, so
29
+ Dependabot, `bundler-audit` and `actions/dependency-review-action` all satisfy
30
+ "dependency risk is reviewed" and a repository that already solved the problem
31
+ its own way is credited instead of asked to adopt ours.
32
+ `SecurityPosture#obligations` says which controls each posture makes binding:
33
+ `strict` blocks without a security policy, dependency review and secret
34
+ scanning; `local` blocks without secret scanning, because committed secrets
35
+ are the one risk that does not care whose runner it is; `balanced` reports the
36
+ same gaps without blocking; `custom` implies nothing, because "no hidden
37
+ relaxation from a preset" cuts both ways.
38
+ - `Evaluators::SecurityEvidence`, a native evaluator that grades one control
39
+ from discovered evidence - so it runs in the read-only default, with no
40
+ execution, and reports a gap as *missing evidence* with the remedy attached
41
+ rather than as a silent pass. Before this, a repository with no security gate
42
+ at all could read **Alive at 100%**: nothing in the contract ever asked.
43
+ - `reanimator contract` now states the posture in plain language and lists
44
+ exactly which controls it requires and which it merely reports. Section 12
45
+ asks for security to be part of onboarding rather than a hidden settings page.
46
+ - Portfolio drift (section 06 applied to the portfolio of section 04).
47
+ `reanimator drift` now takes several paths and returns a triage list rather
48
+ than one verdict: repositories needing a human first, with the reason for each
49
+ policy change; then repositories that merely changed; then the unchanged; then
50
+ the ones with nothing recorded. `PortfolioDrift` is the value object,
51
+ `Reanimator.portfolio_drift(paths)` the library call, and the exit status is
52
+ still non-zero only when something actually needs a decision.
53
+ - `SnapshotStore` decides where a repository's recorded snapshot lives, and is
54
+ the only thing that writes one. The default is **in the repository**,
55
+ committed as `.reanimator-snapshot.json` beside `.reanimator.yml`, so a
56
+ policy change arrives as a diff in a pull request rather than as state hidden
57
+ inside a tool. `--snapshots DIR` keeps them portfolio-side, keyed by
58
+ repository, for repositories you cannot commit a file into.
59
+ - `reanimator drift --record` writes the snapshot where it belongs, so neither
60
+ recording nor comparing needs a remembered path any more: `reanimator drift`
61
+ on its own now compares against the committed snapshot when there is one. The
62
+ reports name the command that re-records *this* snapshot rather than a
63
+ generic `--save FILE`.
64
+
65
+ - Configuration drift (section 06): `ContractSnapshot` records what a
66
+ repository was required to prove at a point in time, and `DriftDetector`
67
+ compares a later resolution against it. Every difference is classified by one
68
+ question — *is less being proven than before?* A narrowed runtime matrix, a
69
+ removed security gate, a dropped required obligation, a widened autonomy
70
+ grant or a fresh waiver are **policy changes** and ask for a human; a renamed
71
+ test command, an added check or a withdrawn waiver are **benign** and do not
72
+ interrupt anyone. The snapshot carries discovered evidence as well as the
73
+ declared file, so drift that never touches `.reanimator.yml` is still seen.
74
+ - CLI: `reanimator drift [--since FILE] [--save FILE]`, exiting non-zero on a
75
+ policy change so CI can gate on it. The only file written is the one named
76
+ with `--save`.
77
+
78
+ - Repository families (section 10): related repositories are treated as a
79
+ compatibility graph rather than isolated targets. `Relationship` carries the
80
+ seven typed edges, `Family` holds members/roles/gates (and parses the section
81
+ 10 family-policy shape), and `FamilyInference` derives families from portfolio
82
+ structure - a project with its `-examples` suite, `-example-*` deployment
83
+ samples, `-docs`, or a `<host>-<project>` plugin. Declaration wins over
84
+ inference on both ends of an edge.
85
+ - `Family::GateRunner` proves each edge by running the downstream member's own
86
+ check (a smoke script, else its discovered tests) read-only, bounded, and in a
87
+ disposable copy - a candidate change upstream triggers downstream checks
88
+ without opening anything downstream. A failure names **the exact edge that
89
+ broke**, not merely the repository that ran.
90
+ - CLI: `reanimator families` and `reanimator gates [--execute] [--family ID]`.
91
+
92
+ - Waivers (section 09): explicit, attributable, optionally time-bounded
93
+ exceptions declared in `.reanimator.yml`. A waived required criterion is
94
+ recorded as **accepted risk** — not counted as verified, kept out of the
95
+ Verified Vitality Rate, and no longer blocking — while an expired waiver
96
+ fails closed. `Waiver`, `EffectiveContract#waiver_for`,
97
+ `Baseline#accepted_risks`/`#unresolved_required`, and accepted-risk reporting.
98
+
99
+ - Canonical domain model: lifecycle intent, vitality profiles (Ruby-first),
100
+ discovered facts with provenance and confidence, acceptance criteria, and the
101
+ proof-of-life state vocabulary.
102
+ - Read-only discovery with detectors for Bundler, Ruby gems, Rails apps,
103
+ discovered commands, GitHub Actions (CI matrix + security controls),
104
+ repository security controls, forks, operational proof, and relationships.
105
+ - Portfolio intake: cohort classification and a recommended onboarding set that
106
+ never preselects everything.
107
+ - `EffectivePolicyResolver` and a non-bypassable `SafetyFloor` implementing the
108
+ section 07 precedence rules (owner declaration wins; nothing loosens the
109
+ floor; merge disabled in v1).
110
+ - `.reanimator.yml` reader/writer with lossless round-trip.
111
+ - Baseline runner with isolated evaluators (command, http-smoke, repository
112
+ integrity, documentation, support matrix), bounded/opt-in execution, and
113
+ proof-of-life assessment.
114
+ - Reporters mirroring the specification artifacts: the GitHub Check surface, the
115
+ full baseline report, the Appendix A portfolio baseline, discovery, contract,
116
+ and inventory.
117
+ - A Thor CLI (`reanimator inventory|discover|contract|baseline|portfolio`).
118
+ - Coding-agent adapters (section 08): a portable `Agents::Adapter` contract, a
119
+ fully working local rule-based agent, and honest hosted-provider stubs
120
+ (Codex/Claude/Amp) that report themselves unavailable until connected.
121
+ - Account/organization `AgentConnection` (credentials referenced, never stored)
122
+ and `AgentProfile` with a commissioned readiness verdict.
123
+ - Commissioning: a six-step synthetic repair against a disposable fixture,
124
+ graded independently by Reanimator's own evaluators, with verifier
125
+ isolation and anti-gaming (a patch that touches a protected/verifier path is
126
+ refused) enforced structurally.
127
+ - Routing (`Routing::Router`): auto, pinned, ordered, task-routed, local-only,
128
+ and manual strategies, each producing a visible explanation; fallback is only
129
+ ever a declared profile that shares the data-handling policy.
130
+ - Autonomy ladder and permission model (section 11): `AutonomyLevel`,
131
+ `TaskClass` defaults, and `PermissionModel` that intersects task-class
132
+ defaults with the repository's enabled autonomy and the safety floor.
133
+ - CLI additions: `reanimator agents|commission|permissions`.
134
+ - Bounded repair (sections 11, 13, 17): `RepairRun` orchestrates baseline →
135
+ obligation → permission check → routing → isolated agent repair → independent
136
+ re-verification → a materialized `ProposedChange` (draft PR), recorded as an
137
+ immutable `Run` in the ledger. It writes nothing to the repository - a
138
+ proposed draft PR is an artifact, and submission is a separate, opt-in step.
139
+ - `Obligation` (idempotent, deduplicated), `ProposedChange`, `Run` (section 17
140
+ ledger), and an `Isolation` disposable-workspace helper.
141
+ - CLI addition: `reanimator repair`.
142
+
143
+ ### Fixed
144
+
145
+ - A criterion whose evaluator **errored** no longer reads as proof. `:error` was
146
+ neither "failed" nor "unproven", so a required check that could not be
147
+ evaluated left the repository green - the one outcome a verifier must never
148
+ produce. "We could not tell" is now unproven.
149
+ - The layers that contribute obligations - profile defaults, posture security
150
+ controls, owner declarations - are merged by criterion id instead of
151
+ concatenated, so a declared check *replaces* the default it names rather than
152
+ appearing twice alongside it. Precedence follows section 07: the owner's
153
+ declaration wins.
154
+ - A portfolio drift run fails closed on a snapshot it cannot read. An
155
+ unreadable or corrupt snapshot is reported as needing review rather than
156
+ counted among the quiet repositories - "we could not tell" is not "nothing
157
+ changed", and corrupting a snapshot file must never be a way to make a drift
158
+ gate pass. A repository with nothing recorded yet is still named without
159
+ failing the gate: that is a first run, not a gap.
160
+ - One unreadable repository no longer ends a portfolio run; it becomes a failed
161
+ entry and every other member still reports.
162
+
163
+ - `reanimator drift --format text` now prints text. With no `--since` it
164
+ described the repository's current obligations in prose instead of emitting
165
+ JSON, which contradicted its own `--format` flag; `--format json` is
166
+ unchanged for machine use.
167
+ - A drift report now ends by saying how to accept drift that was intended,
168
+ naming the exact `--save` command - the build log is the only place the
169
+ maintainer is looking.
170
+ - Drift comparison fails closed and refuses input it cannot trust. A snapshot
171
+ file is ordinary input, so one that is valid JSON but not a snapshot, or a
172
+ path that is a directory, now fails as a clean error instead of a raw
173
+ `TypeError`/`Errno` backtrace - as does `--save` into a directory that does
174
+ not exist. A waiver whose new expiry cannot be parsed is treated as a policy
175
+ change rather than silently filed as "shortened".
176
+ - A recorded `ContractSnapshot` is genuinely immutable: its criteria, paths and
177
+ matrices can no longer be edited after the fact (a bare `freeze` left them
178
+ writable), and recording a contract no longer freezes the live contract.
179
+ - Drift identifies a repository by its git origin when both snapshots carry
180
+ one, so two checkouts that merely share a directory name are refused instead
181
+ of reporting the most dangerous possible answer: "no drift".
182
+
183
+ - Baseline/repair command execution now runs in a disposable copy of the
184
+ repository, never the original working tree (spec section 14), so `gem build`,
185
+ tests, and other checks cannot leave artifacts in the real checkout.
186
+ - Bounded commands run as their own process group and terminate the whole group
187
+ on timeout, so a spawned child cannot outlive the bound.
188
+ - Protected-path matching is depth-correct: a protected `dir/**` now covers
189
+ nested files (e.g. `.github/workflows/nested/*.yml`) instead of only the top
190
+ level, and allow globs cover nested paths too.
191
+ - The `tests` acceptance criterion now carries the provenance of its discovered
192
+ command (a criterion-id/fact-key mismatch previously dropped it).
193
+ - Bounded repair proves agent readiness by commissioning before routing, rather
194
+ than assuming readiness from mere availability.
195
+ - Robust to non-UTF-8 input: repository files and command output are read as
196
+ scrubbed UTF-8, so a stray byte (or a C/US-ASCII locale) no longer makes a
197
+ detector raise, get swallowed, and silently drop facts.
198
+ - `BoundedCommand` caps captured output (1 MiB) so a runaway command cannot
199
+ exhaust memory, while still draining the pipe so the child never blocks.
200
+ - Swallowed detector failures now log their exception class and origin, so a
201
+ hidden bug stays diagnosable instead of silently dropping facts.
202
+ - `Baseline` answers `failing_required`, `unproven_required`,
203
+ `first_failing_required_criterion`, `result_for`, and `verified_required_ids`,
204
+ removing duplicated result-digging from the repair flow and reporters.
205
+
206
+ [Unreleased]: https://github.com/Autogenetica/reanimator/compare/v0.1.0...HEAD
207
+ [0.1.0]: https://github.com/Autogenetica/reanimator/releases/tag/v0.1.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Valentino Stoll
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.