Requested outcome
Complete the SP-RESOURCE-LIFECYCLE chain with its two remaining slices: the live authority and journal boundary, and the runtime composition that finally activates lifecycle behavior.
Follow-up to #173 (whole change) and #176 (service orchestration, delivered by #177/#179/#180). Those issues are closed; this one covers the work that remains.
Current limitation
After #180, the lifecycle core classifies resources and journals evidence, but nothing wires it to a real provider or to the server:
- there is no adapter that observes live PostgreSQL Docker resources or resolves authority records;
- there is no durable journal implementation behind the
LifecycleJournal port;
LifecycleSchedulerGate exists as a Protocol in src/odoo_forge/ports/resource_lifecycle.py with no implementation and no reference in src/odoo_forge_server/composition.py.
As a result the Controlled operations and audit requirement of the orphan-resource-recovery specification is unmet, and its Manual default scenario is unproven: nothing demonstrates that an absent or disabled scheduler runs no automated recovery while manual execution stays available.
Expected behavior
Slice A — live authority and journal (dormant).
- Fixed-argv Docker observation with no shell and validated immutable identifiers. Malformed output, nonzero exit, timeout, and identifier injection or mismatch map to
UNVERIFIABLE with zero mutation.
- Read-only tenant/project authority lookup emitting typed presence evidence; caller scope is never copied into the result.
- Fsynced append-only JSONL journal that reloads immutable run and action records. Recovery verbs delegate without provision or restore.
- The module stays unimported by the server, so no runtime behavior changes.
Slice B — runtime composition.
- Share one registry and one authority instance with the existing control-plane wiring; no second registry.
- Install the Slice A gateway and journal.
- Expose internal manual execution only; add no HTTP route.
- Gate automated runs behind the existing explicit opt-in
LifecycleSchedulerGate, disabled by default.
- Preserve PROD report-only behavior end to end.
Verification
Each slice stays within the 400-line review budget, contains only its own tests and diff, and is independently green and revertible. Whole-change verification runs once after Slice B, covering 4/4 requirements and 10/10 scenarios of the resource-expiration-policy and orphan-resource-recovery specifications.
Scope boundary
Does not touch portfolio, wizard, data-environments, migrations, or backfill. No new flags. No migration or recreation without an explicit separate request.
Requested outcome
Complete the
SP-RESOURCE-LIFECYCLEchain with its two remaining slices: the live authority and journal boundary, and the runtime composition that finally activates lifecycle behavior.Follow-up to #173 (whole change) and #176 (service orchestration, delivered by #177/#179/#180). Those issues are closed; this one covers the work that remains.
Current limitation
After #180, the lifecycle core classifies resources and journals evidence, but nothing wires it to a real provider or to the server:
LifecycleJournalport;LifecycleSchedulerGateexists as a Protocol insrc/odoo_forge/ports/resource_lifecycle.pywith no implementation and no reference insrc/odoo_forge_server/composition.py.As a result the
Controlled operations and auditrequirement of theorphan-resource-recoveryspecification is unmet, and itsManual defaultscenario is unproven: nothing demonstrates that an absent or disabled scheduler runs no automated recovery while manual execution stays available.Expected behavior
Slice A — live authority and journal (dormant).
UNVERIFIABLEwith zero mutation.Slice B — runtime composition.
LifecycleSchedulerGate, disabled by default.Verification
Each slice stays within the 400-line review budget, contains only its own tests and diff, and is independently green and revertible. Whole-change verification runs once after Slice B, covering 4/4 requirements and 10/10 scenarios of the
resource-expiration-policyandorphan-resource-recoveryspecifications.Scope boundary
Does not touch portfolio, wizard, data-environments, migrations, or backfill. No new flags. No migration or recreation without an explicit separate request.