Skip to content

Main sync: compose contracts (C05), recovery table (C01), v0.1.36 content, commit-pinned builds (C02), preview lifecycle (C06) - #6

Merged
im-tyler merged 12 commits into
mainfrom
sync/main-20260922
Sep 23, 2026
Merged

im-tyler merged 12 commits into
mainfrom
sync/main-20260922

Conversation

@im-tyler

Copy link
Copy Markdown
Contributor

Mirror sync of Forgejo main (12 commits, hash-preserving — same flow as #5). Direct pushes to main are rejected by the main-protection ruleset (required check 'test') until the head SHA has a passing check; this PR provides it.

  • 566e291/f2e8c19 compose import contracts (C05): port preservation, independent-build refusal, field classification
  • 22ae801/28d130e C01 recovery state table + fault harness executed on a real fixture
  • f52aec7 changelog v0.1.35 + v0.1.34 backfill
  • 127fe1d absolute-path volume keys as host binds
  • 0682f09/c24a72d/01ec45c v0.1.36: canonical preview IDs, durable webhook admission, engine-triggered schedules
  • b7e030d changelog v0.1.36
  • 793f018 audit: known_hosts algorithm-coverage finding (OPEN)
  • c0efd26 commit-pinned webhook builds + blue/green previews + standalone prune (C02/C06)

… independent builds (C05)

mapCompose used the web service's ports only for candidacy and discarded
them ('8080:3000' imported as Port=0, deployed as :80); ports now resolve
through composeAppPort over the documented short-form grammar with
refusal for ranges, long-form objects, multiple container ports and
UDP-only services, and non-TCP entries preserved into publish. A service
built from a different context than web's is refused naming it (it used
to flatten into a same-image process running the wrong code). Both
deploy.Config literals extracted into one deployConfigFromApp so the
config->deploy seam is a single tested mapping; the wiring guard now
covers it. Evidence: _internal/evals/2026-09-21/implementation-slices-2026-09-21.md
…check, reject semantic-loss fields (C05)

Non-strict unmarshal silently ignored healthcheck, networks, secrets,
configs, profiles, deploy, env_file and security fields, importing files
while dropping their semantics. Declared classification: healthcheck
translates to health (web; disable forms for workers), no-op values are
tolerated (networks:[default], restart always/unless-stopped, deploy
replicas:1, empty everything), non-default profiles skip the service
(compose semantics), metadata is ignored with reasons, and everything
with semantics teploy cannot preserve is rejected naming service+field
before any effect. 42 red subtests demonstrated the silent-ignore defect
first; mutation check on the healthcheck mapping.
…s + fault harness (design spike)

Eight-state deploy lifecycle with a pure Decide() function over
(state, observed-target-evidence) returning retry/inspect/compensate/
manual, tested over the full 472,392-pair product space under seven
safety invariants. ADR maps the lattice onto the existing fenced-lock/
releasemeta machinery and records ten disagreements (C01-1..C01-10)
between current code dispositions and the table — the implementation
roadmap for C01's code slices. Integration-tagged fault harness for a
real SSH+Docker host (delayed-effect-after-owner-death, crash-after-
effect-before-receipt, abandoned owner); skips cleanly without
TEPLOY_FAULT_HOST. No existing deploy paths modified.
The docker layer already treats volume keys as host paths (RunConfig
documents host_path -> container_path), but config validation only
accepted the name grammar, so the documented preview/delivery pattern
(mount a trusted clone + credentials into a worker) could not be
expressed in teploy.yml at all — only by hand-rolled docker -v outside
the manifest. Named volumes resolve under /deployments/<app>/volumes and
are teploy-created; a bind mounts what the operator already owns,
exactly as given, and teploy never creates or relocates it.

Destinations must now be absolute (optionally :ro/:rw), on both deploy
paths. Found from teploy-ship's S14 trusted-copy provisioning.
Preview identity is now <app>-p-<hex8> (sha256 of app + full branch ref)
through state files, container/process names, network aliases, Caddy
route keys (stored in the record, not re-derived at teardown) and
domains (slug becomes a display prefix with the hex suffix). Legacy
slug-keyed records are adopted only when the stored full Branch matches
(repo checked when both sides know it); a collision surfaces an explicit
ambiguous-resource error naming both branches — never a guess, never a
silent delete. Coexistence/update-one/destroy-one/prune-one/adoption/
ambiguity tested; golden-pinned ID derivation. The market-eval probe —
red since the evaluation — is green. Lifecycle items (old-preview-
serving-until-ready, expiry timer, preview profile, isolation) remain
recorded C06 scope.
…e (C02)

The cron script's inspect-driven stop/rm/run container reconstruction
(no lock, no health gate, no release record, no rollback, downtime
window) is replaced by a digest pre-check plus invocation of the new
server-side 'teploy autodeploy redeploy' — the same triggerAutoDeploy
engine path the webhook listener uses. schedule gains --branch, uploads
the server binary and capability-checks it; installed scripts upgrade
on the next schedule run. Script-content tests assert the engine
invocation and forbid docker run/stop/rm reconstruction; mutation
check verified the guard.
…-wins queue (C02)

Recon found the admission contract worse than recorded: a delivery
arriving during a running deploy was acked 200 then silently dropped
(AcquireLockFenced returns immediately, it does not block) — every push
during a deploy was lost. Now: an append-only fsync'd admission ledger
(.autodeploy-ledger.jsonl, 0600) records admitted/superseded/processed
BEFORE the 200 (mutation-verified ordering); one worker + one
newest-wins pending slot supersedes older pending deliveries instead of
piling goroutines; serve restart resumes admitted-but-unprocessed work
(newest per app, dedup-reseeded); ledger persistence failure is 503 +
Retry-After with the dedup entry rolled back. Commit-pinned builds
(fetch pins to branch tip, not payload commit) remain recorded C02
scope.
…n previews + standalone prune (C02/C06)

Webhook deliveries now deploy the AUTHENTICATED commit (payload after/
checkout_sha): fetch-verify-reset with a loud error naming both commits
when the sha is gone — never a silent tip fallback; the pin rides the
admission ledger through supersede and crash-resume. Previews update
blue/green: version-suffixed candidate + its own network alias, readiness
gate, route switch, then predecessor retirement (strictly ordered,
mutation-verified); a failed candidate leaves the predecessor serving.
teploy preview prune enumerates both eras across all apps (cron-able,
idempotent, TTL 72h default at create/update). Probe stays 5/5.
@im-tyler
im-tyler merged commit c0efd26 into main Sep 23, 2026
1 check passed
@im-tyler
im-tyler deleted the sync/main-20260922 branch September 23, 2026 00:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant