Skip to content

Commit 299e55c

Browse files
committed
docs: record slice 68 production branch trigger smoke
1 parent fbfa403 commit 299e55c

7 files changed

Lines changed: 483 additions & 11 deletions

docs/codealmanac-launch/decisions.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ Status: active.
166166
falls back to a `BranchSource` run.
167167
- Conversation-batch runs use the same per-branch delivery policy as branch
168168
runs. The old scheduler path must not hard-code commit delivery.
169+
- Branch-triggered cloud runs are immutable snapshots. The worker must
170+
materialize the run's recorded `head_sha`, and when a range is needed it must
171+
fetch the recorded `before_sha`; it must not run against the live branch tip.
169172

170173
## Naming
171174

docs/codealmanac-launch/next-agent-brief.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,24 @@ Cloud remains the primary product path. Local remains a free/dev surface with a
1212
parallel conceptual model where it is useful, but not a reason to muddy the
1313
cloud setup flow.
1414

15+
## Current Verified State
16+
17+
- Hosted repo branch `codex/workos-authkit-api-foundation` and hosted `main`
18+
both include `eb8dba042c80ed573ad53399f002126d2e14bc29`.
19+
- Render service `srv-d8g8nb37uimc739vnnsg` is live on deploy
20+
`dep-d93pp0eq1p3s73cuomp0`.
21+
- Modal app `codealmanac-hosted-updates` was redeployed after `eb8dba0`.
22+
- Chrome verified signed-in production `/setup` and the production repository
23+
dashboard for `AlmanacCode/codealmanac`.
24+
- Fresh production branch push created run
25+
`773da5fb-9871-4f83-8797-ddf651c635ce`; it delivered with summary
26+
`No wiki changes made.`
27+
- Do not chase older failed smoke runs unless doing cleanup. The old failures
28+
are historical evidence from stale worker images and pre-fix payloads.
29+
- The old conversation-batch run
30+
`aeb55370-cbdd-4ded-af6a-5e0e22f0ef0a` still appears `running` from a stale
31+
pre-fix Modal worker image.
32+
1533
## Last Completed Work
1634

1735
Slice 50 added the browser-owned cloud setup entry:

docs/codealmanac-launch/progress.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Percentages are planning estimates, not accounting metrics.
88

99
## Latest RelayForge Update
1010

11-
Sent: 2026-07-03 after Slice 63 production setup pressure test.
11+
Sent: 2026-07-03 after Slice 68 production branch-trigger smoke.
1212

1313
Route:
1414

@@ -19,21 +19,21 @@ doppler run --project almanac --config dev -- \
1919
--binding rohan-almanac-main "..."
2020
```
2121

22-
Note: production Chrome verified setup, repository list, repository settings,
23-
reversible branch trigger/delivery save, and the CLI setup guide. Hosted
24-
frontend commit `47b1ada` is deployed to Vercel production at
25-
`codealmanac-hosted-gutvigm88-thealmanac.vercel.app` and aliased to
26-
`https://www.codealmanac.com`.
22+
Note: production Chrome verified setup and repository dashboard; Render is live
23+
on hosted commit `eb8dba0`; Modal `codealmanac-hosted-updates` is redeployed;
24+
a fresh GitHub branch push created run
25+
`773da5fb-9871-4f83-8797-ddf651c635ce`, which delivered with summary
26+
`No wiki changes made.`
2727

2828
## Percentages
2929

3030
| Area | Latest | Previous | Basis |
3131
| --- | ---: | ---: | --- |
32-
| CodeAlmanac backend/local | 96% | 96% | CodeAlmanac local/backend unchanged in Slice 63. |
33-
| CodeAlmanac CLI/public UX | 98% | 98% | PyPI `0.1.1` remains published and install-smoked; setup guide remains PyPI-shaped in production. |
34-
| CodeAlmanac-hosted backend/auth/API | 99% | 99% | Backend unchanged in Slice 63; production BFF trigger reads/writes succeeded through the frontend session. |
35-
| Hosted frontend/onboarding | 95% | 92% | Production Chrome verified setup, repository list, settings, live settings summary, reversible branch trigger save/restore, and CLI setup guide after Vercel deploy. |
36-
| Infra/deploy rename | 99% | 99% | Vercel production is live on `47b1ada`; Render remains live on `fdad34d`. |
32+
| CodeAlmanac backend/local | 96% | 96% | CodeAlmanac local/backend unchanged in Slice 68. |
33+
| CodeAlmanac CLI/public UX | 98% | 98% | Published CLI setup/capture were verified in earlier slices; Slice 68 used the CLI to disable the smoke trigger and revoke capture cleanup. |
34+
| CodeAlmanac-hosted backend/auth/API | 99% | 99% | Production branch push now creates an immutable branch-source run and worker completion delivered successfully. |
35+
| Hosted frontend/onboarding | 96% | 95% | Chrome verified signed-in `/setup` and repository dashboard after production fixes; dashboard showed delivered run. |
36+
| Infra/deploy rename | 99% | 99% | Render is live on `eb8dba0`; Modal app `codealmanac-hosted-updates` is redeployed; Vercel frontend unchanged. |
3737

3838
## Update Rule
3939

docs/codealmanac-launch/verification-matrix.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,3 +1292,43 @@ Current evidence:
12921292
- Fresh published CLI setup through real Chrome approved `/cli-login`, stored
12931293
auth in a temp HOME, and `whoami` returned `rohans0509` with cloud
12941294
`https://api.codealmanac.com`.
1295+
1296+
## Slice 68 Production Branch Trigger Smoke
1297+
1298+
- Chrome verified signed-in production `/setup` for `rohans0509` and the
1299+
production repository dashboard for `AlmanacCode/codealmanac`.
1300+
- Production GitHub App `push` webhook delivery is enabled.
1301+
- Hosted commit `03c57f8` fixed branch pushes incorrectly mapping to first-wiki
1302+
initialization by introducing `InitialWikiSource` and mapping `BranchSource`
1303+
to CodeAlmanac ingest.
1304+
- Hosted commit `eb8dba0` fixed branch-source worker checkout determinism:
1305+
branch-like runs now checkout the exact run `head_sha` and fetch
1306+
`before_sha` so `git:range:<before>..<head>` can be evaluated in the Modal
1307+
workspace.
1308+
- Verification passed for `eb8dba0`:
1309+
- `uv run pytest tests/test_github_checkout_contract.py tests/test_modal_worker_contract.py -q`
1310+
(`23 passed`)
1311+
- `uv run pytest tests/test_architecture_contract.py tests/test_github_checkout_contract.py tests/test_modal_worker_contract.py tests/test_updates_contract.py tests/test_repositories_api_contract.py tests/test_cli_runs_api_contract.py -q`
1312+
(`165 passed`, `1` Starlette warning)
1313+
- `uv run ruff check src modal_app tests/test_github_checkout_contract.py tests/test_modal_worker_contract.py`
1314+
- real Git fetch-by-SHA smoke for the exact smoke `before_sha` and `head_sha`
1315+
- Deploy and production smoke passed:
1316+
- Render deploy `dep-d93pp0eq1p3s73cuomp0` is live on hosted commit
1317+
`eb8dba042c80ed573ad53399f002126d2e14bc29`.
1318+
- Modal app `codealmanac-hosted-updates` was redeployed after the checkout
1319+
fix.
1320+
- Disposable branch push created run
1321+
`773da5fb-9871-4f83-8797-ddf651c635ce` with immutable source range
1322+
`d11d29b96dbfe334b2d9cb99fa5aafcc7893d98a..23a0a03209ff1804944eb094f589647dc13de47b`.
1323+
- The run delivered with summary `No wiki changes made.`
1324+
- Chrome refreshed the production dashboard and showed the delivered run at
1325+
the top.
1326+
- Cleanup completed: smoke trigger disabled, temp capture credential revoked,
1327+
remote smoke branch deleted, temp worktree removed.
1328+
1329+
Known residue:
1330+
1331+
- Older failed smoke runs remain visible and should be treated as historical
1332+
evidence.
1333+
- Conversation-batch run `aeb55370-cbdd-4ded-af6a-5e0e22f0ef0a` is still
1334+
marked `running` from a stale pre-fix Modal image.

docs/codealmanac-launch/worklog.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,3 +1894,31 @@
18941894
`CLI login approved`, setup finished signed in as `rohans0509`, `whoami`
18951895
returned cloud `https://api.codealmanac.com`, and `capture status
18961896
--check-cloud --json` reached production with `signed_in: true`.
1897+
- Slice 68 production branch-trigger smoke passed after two worker fixes.
1898+
Chrome verified signed-in `/setup` and the production repository dashboard
1899+
for `AlmanacCode/codealmanac`. GitHub App `push` delivery is enabled.
1900+
- Slice 68 found the first worker bug through production: branch pushes were
1901+
being treated like first wiki initialization. Hosted commit `03c57f8`
1902+
introduced `InitialWikiSource` and mapped `BranchSource` to ingest.
1903+
- Slice 68 found the second worker bug through production: branch-source
1904+
workers cloned the live branch at depth 1 instead of materializing the exact
1905+
run snapshot. Hosted commit `eb8dba0` makes branch-like runs checkout the
1906+
exact `head_sha` and fetch `before_sha` for `git:range`.
1907+
- Verification for `eb8dba0` passed: hosted backend tests
1908+
`test_architecture_contract.py`, `test_github_checkout_contract.py`,
1909+
`test_modal_worker_contract.py`, `test_updates_contract.py`,
1910+
`test_repositories_api_contract.py`, and `test_cli_runs_api_contract.py`
1911+
(`165 passed`, `1` Starlette warning), hosted ruff, and a real Git
1912+
fetch-by-SHA smoke against the public CodeAlmanac repo.
1913+
- Render deploy `dep-d93pp0eq1p3s73cuomp0` is live on hosted commit
1914+
`eb8dba0`. Modal app `codealmanac-hosted-updates` was redeployed from the
1915+
same checkout.
1916+
- Fresh production push to disposable branch
1917+
`codealmanac-smoke/slice-68-20260703102325` created run
1918+
`773da5fb-9871-4f83-8797-ddf651c635ce` with
1919+
`before_sha=d11d29b96dbfe334b2d9cb99fa5aafcc7893d98a` and
1920+
`head_sha=23a0a03209ff1804944eb094f589647dc13de47b`. The run delivered with
1921+
summary `No wiki changes made.`
1922+
- Chrome refreshed the production dashboard and showed the delivered run at the
1923+
top. Cleanup completed: smoke trigger disabled, temp capture credential
1924+
revoked, remote smoke branch deleted, temp worktree removed.
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
# GitHub Webhook Contract Hardening Implementation Plan
2+
3+
Status: planned research artifact. Use as the starting point before changing
4+
GitHub webhook intake again.
5+
6+
**Goal:** Make hosted CodeAlmanac's GitHub webhook intake match GitHub's event schemas for the webhook families we depend on, without adding reconciliation or a parallel sync path.
7+
8+
**Architecture:** Route webhook parsing by `X-GitHub-Event`, normalize supported payloads into typed Pydantic messages, and audit unsupported payloads as ignored. Control-plane messages carry the parent provider facts they need; fanout subscribers keep owning their own tables.
9+
10+
**Tech Stack:** FastAPI, SQLModel, Pydantic, GitHub App webhooks, Octokit generated webhook schemas for research.
11+
12+
---
13+
14+
## Research Baseline
15+
16+
Checked on 2026-07-03:
17+
18+
- GitHub docs: `https://docs.github.com/en/webhooks/webhook-events-and-payloads`
19+
- GitHub Apps webhook docs: `https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/using-webhooks-with-github-apps`
20+
- `@octokit/webhooks-schemas@7.6.1`: 66 top-level event families, 224 action variants.
21+
- `@octokit/webhooks-examples@7.6.1`: current dotcom examples for 58 event families.
22+
23+
The current backend supports only these event families:
24+
25+
```text
26+
installation
27+
installation_repositories
28+
repository
29+
push
30+
pull_request
31+
```
32+
33+
That scope is correct for launch. The bug is not that we ignore most GitHub events; the bug is that the mapper currently guesses by payload shape instead of using `X-GitHub-Event`, and the `installation` action names do not match the schema.
34+
35+
## Important Schema Findings
36+
37+
`installation` actions are:
38+
39+
```text
40+
created
41+
deleted
42+
new_permissions_accepted
43+
suspend
44+
unsuspend
45+
```
46+
47+
Current code checks `suspended` and `unsuspended`, which is wrong.
48+
49+
`installation_repositories` actions are:
50+
51+
```text
52+
added
53+
removed
54+
```
55+
56+
Each payload includes:
57+
58+
```text
59+
installation
60+
repository_selection
61+
repositories_added
62+
repositories_removed
63+
requester
64+
sender
65+
```
66+
67+
The `installation.account` object is present there, so the mapper can produce `AccountSnapshot` and `InstallationSnapshot` for delta events without calling GitHub again.
68+
69+
Most repository-scoped events include these optional or required top-level objects:
70+
71+
```text
72+
installation
73+
repository
74+
organization
75+
sender
76+
```
77+
78+
That does not mean CodeAlmanac should persist every event. It means the webhook edge should route by event name, validate only supported families, and record unsupported families as ignored.
79+
80+
## Out Of Scope
81+
82+
- No login-time GitHub reconciler.
83+
- No background reconciler.
84+
- No broad "sync all installations" repair job.
85+
- No runtime dependency on Node or Octokit.
86+
- No modeling all 66 GitHub webhook families as Python messages.
87+
- No subscription expansion unless product work needs the event.
88+
89+
## Target Shape
90+
91+
```python
92+
message = github_webhooks.parse_github_message(event_name, payload)
93+
94+
match event_name:
95+
case "installation":
96+
return parse_installation(payload)
97+
case "installation_repositories":
98+
return parse_installation_repositories(payload)
99+
case "repository":
100+
return parse_repository(payload)
101+
case "push":
102+
return parse_push(payload)
103+
case "pull_request":
104+
return parse_pull_request(payload)
105+
case _:
106+
return None
107+
```
108+
109+
Supported control-plane messages carry parent snapshots:
110+
111+
```python
112+
InstallationRepositoriesAdded(
113+
account=AccountSnapshot(...),
114+
installation=InstallationSnapshot(...),
115+
repository_selection="selected",
116+
repositories=[...],
117+
)
118+
```
119+
120+
Identity fanout handles the parent rows:
121+
122+
```python
123+
identity.on_installation_repositories_added(message):
124+
accounts.upsert(message.account)
125+
installations.upsert(message.installation)
126+
```
127+
128+
Repository fanout handles repository scope only:
129+
130+
```python
131+
repositories.on_installation_repositories_added(message):
132+
repository_scope.sync_installation(message.installation.installation_id)
133+
```
134+
135+
## Implementation Tasks
136+
137+
### Task 1: Route Parsing By GitHub Event Header
138+
139+
**Files:**
140+
141+
- Modify: `backend/src/almanac/services/github/service.py`
142+
- Modify: `backend/src/almanac/services/github/webhooks.py`
143+
- Test: `backend/tests/test_github_service_contract.py`
144+
145+
Steps:
146+
147+
1. Change `GitHubService.handle_webhook` to call `parse_github_message(event, payload)`.
148+
2. Replace shape-sniffing in `map_payload(payload)` with event-name dispatch.
149+
3. Keep unsupported event families returning `None`.
150+
4. Add tests showing unsupported `check_run` / `check_suite` remain ignored.
151+
5. Add a regression test showing a payload with both `repository` and `installation` is routed by event name, not shape.
152+
153+
### Task 2: Correct Installation Action Contract
154+
155+
**Files:**
156+
157+
- Modify: `backend/src/almanac/services/github/webhooks.py`
158+
- Modify: `backend/src/almanac/services/github/webhook_messages.py`
159+
- Test: `backend/tests/test_github_service_contract.py`
160+
161+
Steps:
162+
163+
1. Accept `suspend` and `unsuspend`.
164+
2. Stop accepting non-schema `suspended` and `unsuspended`.
165+
3. Map `suspend` to `InstallationSuspended`.
166+
4. Map `unsuspend` to `InstallationUnsuspended`.
167+
5. Ignore `new_permissions_accepted` unless product behavior requires it later.
168+
169+
### Task 3: Carry Parent Snapshots On Installation Repository Deltas
170+
171+
**Files:**
172+
173+
- Modify: `backend/src/almanac/messages/github.py`
174+
- Modify: `backend/src/almanac/services/github/webhook_messages.py`
175+
- Modify: `backend/src/almanac/wiring/fanout/identity.py`
176+
- Test: `backend/tests/test_installations_contract.py`
177+
- Test: `backend/tests/test_github_service_contract.py`
178+
179+
Steps:
180+
181+
1. Add `account: AccountSnapshot` and `installation: InstallationSnapshot` to `InstallationRepositoriesAdded`.
182+
2. Add the same fields to `InstallationRepositoriesRemoved`.
183+
3. Populate those snapshots from `installation.account` and `installation.id`.
184+
4. Subscribe identity fanout to both delta message types.
185+
5. Upsert account and installation in identity fanout before repository fanout syncs repositories.
186+
6. Keep repository fanout focused on `RepositoryScope`.
187+
188+
### Task 4: Add Schema Guardrails For Supported Families
189+
190+
**Files:**
191+
192+
- Modify: `backend/tests/test_github_service_contract.py`
193+
- Optional create: `backend/tests/fixtures/github_webhooks/README.md`
194+
195+
Steps:
196+
197+
1. Add compact fixture payloads for the five supported event families.
198+
2. Include action coverage for:
199+
- `installation.created`
200+
- `installation.deleted`
201+
- `installation.suspend`
202+
- `installation.unsuspend`
203+
- `installation_repositories.added`
204+
- `installation_repositories.removed`
205+
- `repository.renamed`
206+
- `repository.transferred`
207+
- `repository.deleted`
208+
- `push`
209+
- supported `pull_request` actions
210+
3. Assert ignored actions are audited as ignored, not invalid.
211+
4. Assert malformed supported payloads are audited as invalid.
212+
213+
### Task 5: Update Launch Docs
214+
215+
**Files:**
216+
217+
- Modify: `docs/codealmanac-launch/worklog.md`
218+
- Modify: `docs/codealmanac-launch/progress.md`
219+
- Modify: `docs/codealmanac-launch/verification-matrix.md`
220+
- Modify: `docs/codealmanac-launch/next-agent-brief.md`
221+
- Optional modify: `docs/codealmanac-launch/auth-api-contract.md`
222+
223+
Steps:
224+
225+
1. Record the schema inventory result.
226+
2. Record that reconciliation remains out of scope.
227+
3. Record that webhook parsing is event-header routed.
228+
4. Update percentages only after tests and deployment.
229+
230+
## Verification
231+
232+
Run in hosted repo:
233+
234+
```bash
235+
cd /Users/rohan/.config/superpowers/worktrees/usealmanac/hosted-baseline-convergence
236+
uv run pytest backend/tests/test_github_service_contract.py backend/tests/test_installations_contract.py -q
237+
uv run pytest backend/tests/test_repositories_contract.py backend/tests/test_wiki_contract.py -q
238+
uv run ruff check backend/src backend/tests
239+
```
240+
241+
If backend changes pass, deploy hosted backend/frontend together only after the coherent slice is complete.
242+
243+
## Decision Check
244+
245+
This plan fixes real contract drift and the DB-wipe webhook edge without making DB wipe a supported product workflow. If we later want first-class repair, that should be a separate reconciler design with explicit product semantics.

0 commit comments

Comments
 (0)