Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
261 commits
Select commit Hold shift + click to select a range
63ee6aa
chore(porch): 321 acknowledge context refresh
OdyAsh Oct 25, 2026
59dc1cc
[Spec 321][Phase: import_service] feat: Import Python WhatsApp servic…
OdyAsh Oct 25, 2026
de3278a
[Spec 321][Phase: import_service] test: Add conftest with mock-mode d…
OdyAsh Oct 25, 2026
40cd648
chore(porch): 321 implement build-complete
OdyAsh Oct 25, 2026
7b04c55
[Spec 321][Phase: import_service] fix: Add whatsapp CI job, declare r…
OdyAsh Oct 25, 2026
241de4c
[Spec 321][Phase: import_service] docs: Rebuttal for iteration 1 review
OdyAsh Oct 25, 2026
2dbe2a7
chore(porch): 321 implement re-iter (iter 2)
OdyAsh Oct 25, 2026
60dbb96
chore(porch): 321 implement build-complete
OdyAsh Oct 25, 2026
0bdb124
[Spec 321][Phase: import_service] docs: Record review notes, fix conf…
OdyAsh Oct 25, 2026
c816219
chore(porch): 321 advance plan phase → auth_token_exchange
OdyAsh Oct 25, 2026
5f1ebf3
[Spec 321][Phase: auth_token_exchange] feat: Identify users by BSUID …
OdyAsh Oct 25, 2026
c03fba2
chore(porch): 321 implement build-complete
OdyAsh Oct 25, 2026
dddeb00
chore(porch): 321 acknowledge context refresh
OdyAsh Oct 25, 2026
299cdc9
[Spec 321][Phase: auth_token_exchange] fix: Address iteration 1 review
OdyAsh Oct 25, 2026
f59e74c
chore(porch): 321 advance plan phase → thread_lifecycle
OdyAsh Oct 25, 2026
bb1d73e
chore(porch): 321 implement build-complete
OdyAsh Oct 25, 2026
e5a60ac
chore(porch): 321 acknowledge context refresh
OdyAsh Oct 25, 2026
e481f7f
[Spec 321][Phase: thread_lifecycle] feat: One thread per user, replac…
OdyAsh Oct 25, 2026
9aae949
[Spec 321][Phase: thread_lifecycle] fix: Cover Z timestamps and missi…
OdyAsh Oct 25, 2026
a830d90
chore(porch): 321 advance plan phase → environments_and_docs
OdyAsh Oct 25, 2026
c859815
[Spec 321][Phase: environments_and_docs] feat: Use the /chat event st…
OdyAsh Oct 25, 2026
e3cbca0
[Spec 321][Phase: environments_and_docs] feat: Railway JSON logs, req…
OdyAsh Oct 25, 2026
22d44c1
[Spec 321][Phase: environments_and_docs] docs: rewrite whatsapp READM…
OdyAsh Oct 25, 2026
cc21d09
[Spec 321][Phase: environments_and_docs] chore: railway record, repo-…
OdyAsh Oct 26, 2026
ccdc1bd
[Spec 321][Phase: environments_and_docs] feat: MOCK_AUTH_TOKEN for ru…
OdyAsh Oct 26, 2026
6c4de64
[Spec 321][Phase: environments_and_docs] fix: never log the webhook v…
OdyAsh Oct 26, 2026
63ffdb8
[Spec 321][Phase: environments_and_docs] docs: document REAL_TEST_BSU…
OdyAsh Oct 26, 2026
b4f14df
[Spec 324] Add native Google and Apple authentication specification
deeseeker Oct 26, 2026
1e5a69c
[Spec 324] Use react-native-nitro-google-signin for native Google sig…
deeseeker Oct 26, 2026
d4ab7ec
[Spec 321][Phase: environments_and_docs] docs: record real-Meta run, …
OdyAsh Oct 27, 2026
95e3033
chore(porch): 321 acknowledge context refresh
OdyAsh Oct 27, 2026
8f3d997
chore(porch): 321 implement build-complete
OdyAsh Oct 27, 2026
2820811
[Spec 321][Phase: environments_and_docs] fix: address phase review (d…
OdyAsh Oct 27, 2026
7255035
chore(porch): 321 all plan phases complete → review
OdyAsh Oct 27, 2026
b0ab065
chore(porch): 321 acknowledge context refresh
OdyAsh Oct 27, 2026
474db46
[Spec 321] docs: review document, architecture and lessons updates
OdyAsh Oct 27, 2026
458ebec
chore(porch): 321 review build-complete
OdyAsh Oct 27, 2026
aa570ea
[Spec 321] fix: address PR review (mock-token guard, whatsapp-only th…
OdyAsh Oct 27, 2026
f852ce9
chore(porch): 321 review re-iter (iter 2)
OdyAsh Oct 27, 2026
9892b74
chore(porch): 321 review build-complete
OdyAsh Oct 27, 2026
e304861
[Spec 321] fix: address PR review iteration 2 (no apps/api error body…
OdyAsh Oct 27, 2026
6a54d22
[Spec 321] docs: iteration 2 rebuttal and review context
OdyAsh Oct 27, 2026
ee5d490
chore(porch): 321 pr gate-requested
OdyAsh Oct 27, 2026
f8bd0eb
chore(porch): 321 pr gate-approved
OdyAsh Oct 27, 2026
11a15e7
chore(porch): 321 verify phase-transition
OdyAsh Oct 27, 2026
2cb863a
[Plan 324] Add implementation plan for native Google and Apple authen…
deeseeker Oct 27, 2026
0696b98
chore(porch): 329 init spir
amrmelsayed Oct 28, 2026
a95f43a
[Spec 329] Initial specification draft
amrmelsayed Oct 28, 2026
a66c58c
chore(porch): 329 specify build-complete
amrmelsayed Oct 28, 2026
c62d7b6
[Spec 329] Specification with multi-agent review
amrmelsayed Oct 28, 2026
3eef81b
chore(porch): 329 spec-approval gate-requested
amrmelsayed Oct 28, 2026
42a964a
[Spec 329] Specify iteration 1 reviews and rebuttal
amrmelsayed Oct 28, 2026
e7366dc
[Spec 329] Specification with user feedback: noreply.askansari.ai add…
amrmelsayed Oct 28, 2026
45e7d49
[Spec 329] Specification revised for security review (iteration 2)
amrmelsayed Oct 28, 2026
8522f6f
[Spec 329] Specification with owner decisions and security review rou…
amrmelsayed Oct 28, 2026
499e801
[Spec 329] Fix stale test scenario 14 (sanity bounds, not 400)
amrmelsayed Oct 28, 2026
2f432fa
[Spec 329] Record owner decisions 3 (deferred to plan) and 4 (later)
amrmelsayed Oct 28, 2026
f709c13
chore(porch): 329 spec-approval gate-approved
amrmelsayed Oct 28, 2026
c1cd689
chore(porch): 329 plan phase-transition
amrmelsayed Oct 28, 2026
ace2b24
chore(porch): 329 plan build-complete
amrmelsayed Oct 28, 2026
2a60f24
[Spec 329] Initial implementation plan
amrmelsayed Oct 28, 2026
cd1ebb1
[Spec 329] Limits sized by judgement (owner decision 3): initial valu…
amrmelsayed Oct 28, 2026
124d115
[Spec 329] Plan with multi-agent review
amrmelsayed Oct 28, 2026
062c3af
chore(porch): 329 plan-approval gate-requested
amrmelsayed Oct 28, 2026
d313e15
[Spec 329] Plan revised for security plan review
amrmelsayed Oct 28, 2026
fde7794
[Spec 329] Rename the MCP service account to ansari-mcp (owner)
amrmelsayed Oct 28, 2026
5361e8d
[Spec 329] Scheduled key rotation and secret-scanning patterns (owner)
amrmelsayed Oct 28, 2026
03dd26e
chore(porch): 329 plan-approval gate-approved
amrmelsayed Oct 28, 2026
1aa66cf
chore(porch): 329 implement phase-transition
amrmelsayed Oct 28, 2026
427f8fd
[Spec 329][Phase: phase_1] feat: api-key plugin, schema and migration…
amrmelsayed Oct 28, 2026
0b2315e
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
6d9bc6a
[Spec 329][Phase: phase_1] test: probe 1b covers every limit field; a…
amrmelsayed Oct 28, 2026
92181c1
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 28, 2026
b1fd08f
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
a288348
chore(porch): 329 advance plan phase → phase_2
amrmelsayed Oct 28, 2026
25eee8a
chore(porch): 329 acknowledge context refresh
amrmelsayed Oct 28, 2026
362247b
[Spec 329][Phase: phase_2] feat: redact better-auth's logger to {name…
amrmelsayed Oct 28, 2026
a58f516
[Spec 329][Phase: phase_2] docs: state only what the logger test veri…
amrmelsayed Oct 28, 2026
bf61f95
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
b1ccfa2
chore(porch): bugfix-330 init bugfix
amrmelsayed Oct 28, 2026
0658aa0
[Spec 329][Phase: 2] chore(test): own 100 s setup deadline for secret…
amrmelsayed Oct 28, 2026
8102875
[Spec 329][Phase: phase_2] docs: flaky-test measurement and evidence
amrmelsayed Oct 28, 2026
940e93b
[Spec 329][Phase: phase_1] chore: phase 1 iteration 2 review record
amrmelsayed Oct 28, 2026
7221dd5
[Spec 329][Phase: phase_2] chore: phase 2 review record
amrmelsayed Oct 28, 2026
2c4d9d5
chore(porch): 329 advance plan phase → phase_3
amrmelsayed Oct 28, 2026
8adaec4
chore(porch): 329 acknowledge context refresh
amrmelsayed Oct 28, 2026
6b1a64a
[Spec 329][Phase: phase_3] feat: reserve the noreply.askansari.ai dom…
amrmelsayed Oct 28, 2026
06da6bc
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
f8f1032
[Spec 329][Phase: phase_3] docs: spec states the padded-address behav…
amrmelsayed Oct 28, 2026
b1cb3b3
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 28, 2026
80f6e9f
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
eeb026d
[Spec 329][Phase: phase_3] test: pin no-oracle as a byte comparison a…
amrmelsayed Oct 28, 2026
9e2991e
[Spec 329][Phase: phase_3] chore: phase 3 review record
amrmelsayed Oct 28, 2026
511ec7c
chore(porch): 329 advance plan phase → phase_4
amrmelsayed Oct 28, 2026
d93945a
chore(porch): 329 acknowledge context refresh
amrmelsayed Oct 28, 2026
7561cbf
[Spec 329][Phase: phase_4] feat: service users and the service-keys o…
amrmelsayed Oct 28, 2026
9a7e866
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
9a746f1
[Spec 329][Phase: phase_4] fix: print the database host before connec…
amrmelsayed Oct 28, 2026
4ca35c7
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 28, 2026
921f885
[Spec 329][Phase: phase_4] chore: phase 4 iteration 1 review record
amrmelsayed Oct 28, 2026
74b9443
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
776ac8a
[Spec 329][Phase: phase_4] fix: keep the raw key out of Sentry breadc…
amrmelsayed Oct 28, 2026
8bed176
chore(porch): 329 implement re-iter (iter 3)
amrmelsayed Oct 28, 2026
81b8bca
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
151aebf
[Spec 329][Phase: phase_4] chore: phase 4 review record (iteration 3,…
amrmelsayed Oct 28, 2026
744fc21
chore(porch): 329 advance plan phase → phase_5
amrmelsayed Oct 28, 2026
0554169
chore(porch): 329 acknowledge context refresh
amrmelsayed Oct 28, 2026
c563d13
chore(porch): bugfix-330 fix phase-transition
amrmelsayed Oct 28, 2026
90aff8c
[Spec 329][Phase: phase_5] chore: gate before phase 5, probes rerun o…
amrmelsayed Oct 28, 2026
c220e87
[Spec 329][Phase: phase_5] feat: WhatsApp identity and session core
amrmelsayed Oct 28, 2026
55184cd
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
b14cc3c
[Spec 329][Phase: phase_5] fix: pin the exchange JWT's kid; review it…
amrmelsayed Oct 28, 2026
9ddb070
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 28, 2026
def0f80
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
8e20172
[Spec 329] spec: signJWT runs after the commit (amendment, security a…
amrmelsayed Oct 28, 2026
80d0357
[Spec 329][Phase: phase_5] chore: phase 5 review record (iteration 2,…
amrmelsayed Oct 28, 2026
9ffc374
chore(porch): 329 advance plan phase → phase_6
amrmelsayed Oct 28, 2026
250140f
chore(porch): 329 acknowledge context refresh
amrmelsayed Oct 28, 2026
eca50af
[Bugfix #330] Pre-register the capped/uncapped A/B protocol before ru…
amrmelsayed Oct 28, 2026
5747330
Fix #330: cap vitest workers in the root test script
amrmelsayed Oct 28, 2026
14f6c68
[Spec 329][Phase: phase_6] feat: WhatsApp exchange route, boot assert…
amrmelsayed Oct 28, 2026
0253700
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
74ddc37
[Spec 329][Phase: phase_6] fix: bind the boot constraint check to aut…
amrmelsayed Oct 28, 2026
6f2044a
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 28, 2026
5aa6e1a
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
631c2f7
[Spec 329][Phase: phase_6] chore: phase 6 review record (iteration 2,…
amrmelsayed Oct 28, 2026
af2994c
chore(porch): 329 advance plan phase → phase_7
amrmelsayed Oct 28, 2026
0908487
chore(porch): 329 acknowledge context refresh
amrmelsayed Oct 28, 2026
09a46b2
[Spec 329][Phase: phase_7] feat: end-to-end exchange contract test, w…
amrmelsayed Oct 28, 2026
6798f9c
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
3b26450
[Spec 329][Phase: phase_7] fix: document WHATSAPP_KEY_BOUNDS ranges, …
amrmelsayed Oct 28, 2026
fcaca1d
[Spec 329][Phase: phase_7] chore: record an unreproduced @ansari/auth…
amrmelsayed Oct 28, 2026
c9e2fb6
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 28, 2026
f239f8b
chore(porch): 329 implement build-complete
amrmelsayed Oct 28, 2026
20b5060
[Spec 329][Phase: phase_7] chore: phase 7 review record (iteration 2,…
amrmelsayed Oct 28, 2026
706dda7
chore(porch): 329 all plan phases complete → review
amrmelsayed Oct 28, 2026
508d7bc
chore(porch): 329 acknowledge context refresh
amrmelsayed Oct 28, 2026
8291328
[Spec 329][Phase: review] docs: review document, lessons routed (cold…
amrmelsayed Oct 28, 2026
9113053
chore(porch): 329 record PR #331
amrmelsayed Oct 28, 2026
d92da0e
chore(porch): 329 review build-complete
amrmelsayed Oct 28, 2026
6c99ba1
[Spec 329][Phase: review] fix: pin grant-admin revoke on noreply (dem…
amrmelsayed Oct 28, 2026
4afa969
chore(porch): 329 review re-iter (iter 2)
amrmelsayed Oct 28, 2026
ccb3944
chore(porch): 329 review build-complete
amrmelsayed Oct 28, 2026
5ce51d8
[Spec 329][Phase: review] fix: gitleaks allowlist for history-only pr…
amrmelsayed Oct 28, 2026
4495396
[Spec 329][Phase: review] docs: gitleaks run and negative control in …
amrmelsayed Oct 28, 2026
6e5d2c5
[Bugfix #330] Review: A/B results, idle wall time, warm-cache pin proof
amrmelsayed Oct 28, 2026
a7471f5
chore(porch): bugfix-330 pr phase-transition
amrmelsayed Oct 28, 2026
485e55f
[Spec 329][Phase: review] fix: security PR-gate pass 2 (no Sentry bre…
amrmelsayed Oct 28, 2026
e225593
Fix #330: pin the exact root test script and cover test:coverage's ca…
amrmelsayed Oct 28, 2026
2982df9
[Bugfix #330] Thread: PR and CMAP
amrmelsayed Oct 28, 2026
4a902bb
chore(porch): bugfix-330 pr gate-requested
amrmelsayed Oct 28, 2026
cb2daf6
Fix #330: cite the concurrent-run A/B as the pin's proof
amrmelsayed Oct 28, 2026
681efb1
[Spec 329][Phase: review] fix: security PR-gate pass 1 (role allowlis…
amrmelsayed Oct 28, 2026
d177e80
[Spec 329][Phase: review] docs: deploy order per owner decision (stag…
amrmelsayed Oct 28, 2026
0c2da21
[Spec 329][Phase: review] fix(cutover): apply the whole auth journal …
amrmelsayed Oct 28, 2026
05554db
[Spec 329][Phase: review] fix(cutover): copy.sh --dry-run applies the…
amrmelsayed Oct 28, 2026
b7f533e
[Spec 329][Phase: review] docs: main's items A and B in the review, w…
amrmelsayed Oct 28, 2026
f10df8d
[Spec 329][Phase: review] fix(cutover): set -o pipefail before the jo…
amrmelsayed Oct 28, 2026
abc5d61
chore(porch): 329 pr gate-requested
amrmelsayed Oct 28, 2026
e3bc585
chore(porch): bugfix-333 init bugfix
amrmelsayed Oct 28, 2026
d79438b
chore(porch): bugfix-333 fix phase-transition
amrmelsayed Oct 28, 2026
63a25c0
[Bugfix #333] fix: keep request bodies, bearers and cookies out of Se…
amrmelsayed Oct 28, 2026
bd84492
chore(porch): bugfix-333 pr phase-transition
amrmelsayed Oct 28, 2026
64894e9
[Bugfix #333] fix: drop the partial dataCollection option in apps/api
amrmelsayed Oct 28, 2026
9450849
[Plan 324] Address review feedback on web ID token flow, nonce, and p…
deeseeker Oct 28, 2026
e0b9142
Merge remote-tracking branch 'upstream/develop' into builder/spir-321
OdyAsh Oct 29, 2026
c27efbf
[Spec 321] Address review: move to legacy/whatsapp, harden startup an…
OdyAsh Oct 29, 2026
d0b573d
Merge remote-tracking branch 'origin/develop' into builder/bugfix-330
amrmelsayed Oct 29, 2026
f5c40a6
[Bugfix #330] Review: develop merge and re-run pin proof
amrmelsayed Oct 29, 2026
2959c41
[Bugfix #330] Review: quote the merged root test script
amrmelsayed Oct 29, 2026
8136368
[Spec 321] Count the whatsapp CI job as a required check
amrmelsayed Oct 29, 2026
6570cee
Merge pull request #328 from deeseeker/plan/324-native-google-apple-auth
amrmelsayed Oct 29, 2026
54f3751
Merge pull request #327 from OdyAsh/builder/spir-321
amrmelsayed Oct 29, 2026
f169454
Merge remote-tracking branch 'origin/develop' into builder/bugfix-330
amrmelsayed Oct 29, 2026
62dbe6f
Merge remote-tracking branch 'origin/develop' into builder/spir-329
amrmelsayed Oct 29, 2026
8ae8b7a
[Bugfix #333] fix: drop the query string from apps/api Sentry events
amrmelsayed Oct 29, 2026
4797c1e
[Spec 329] chore: thread note for the develop merge
amrmelsayed Oct 29, 2026
6eb3a99
chore(porch): bugfix-330 pr gate-approved
amrmelsayed Oct 29, 2026
fb19e4b
Merge pull request #332 from iaser-ai/builder/bugfix-330
amrmelsayed Oct 29, 2026
fc24553
chore(porch): bugfix-333 pr gate-requested
amrmelsayed Oct 29, 2026
d94f9b7
[Bugfix #333] fix: drop the client IP from apps/api Sentry events
amrmelsayed Oct 29, 2026
9ca21c7
[Bugfix #333] fix: close apps/api's URL, breadcrumb and IP routes; ke…
amrmelsayed Oct 29, 2026
5930f75
chore(porch): bugfix-333 pr gate-approved
amrmelsayed Oct 29, 2026
81ad570
Merge pull request #334 from iaser-ai/builder/bugfix-333
amrmelsayed Oct 29, 2026
51c5291
Merge remote-tracking branch 'origin/develop' into builder/spir-329
amrmelsayed Oct 29, 2026
1d84f91
[Spec 329] Owner amendment 2026-10-30: phone-number plugin and claimi…
amrmelsayed Oct 29, 2026
ca1452d
[Spec 329] Owner amendment: claim vs supersede, unlink, resolved poin…
amrmelsayed Oct 29, 2026
814aa60
chore(porch): 329 rollback review → plan
amrmelsayed Oct 29, 2026
d3b92b0
[Spec 329] Plan: phase 8, phone-number plugin, verified numbers, clai…
amrmelsayed Oct 29, 2026
9f836e2
chore(porch): 329 plan build-complete
amrmelsayed Oct 29, 2026
d2b0cba
chore(porch): 329 plan re-iter (iter 2)
amrmelsayed Oct 29, 2026
ff9f642
chore(porch): 329 plan build-complete
amrmelsayed Oct 29, 2026
7d1a163
[Spec 329] Owner amendment 2: no phone number (withdraws amendment 1)…
amrmelsayed Oct 29, 2026
45235cf
chore(porch): 329 plan-approval gate-requested
amrmelsayed Oct 29, 2026
a2a1674
[Spec 329] Review: phase 8 step 1, 0001 applied nowhere (owner's record)
amrmelsayed Oct 29, 2026
c74fb07
chore(porch): 329 plan-approval gate-approved
amrmelsayed Oct 29, 2026
4204a9e
chore(porch): 329 implement phase-transition
amrmelsayed Oct 29, 2026
7f28a7e
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
67fce13
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 29, 2026
0724472
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
89a2276
chore(porch): 329 advance plan phase → phase_2
amrmelsayed Oct 29, 2026
2f2585b
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
a5830c1
chore(porch): 329 advance plan phase → phase_3
amrmelsayed Oct 29, 2026
61b6807
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
658ff50
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 29, 2026
fa7734d
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
d77c10e
chore(porch): 329 advance plan phase → phase_4
amrmelsayed Oct 29, 2026
b702ff1
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
f637e7e
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 29, 2026
29bbe70
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
752c9fa
chore(porch): 329 implement re-iter (iter 3)
amrmelsayed Oct 29, 2026
47daf87
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
19331df
chore(porch): 329 advance plan phase → phase_5
amrmelsayed Oct 29, 2026
1d028df
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
e33f9d5
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 29, 2026
c581ad7
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
db3e7bb
chore(porch): 329 advance plan phase → phase_6
amrmelsayed Oct 29, 2026
ecd53a2
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
97ccb99
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 29, 2026
a3b0cce
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
7c43820
chore(porch): 329 advance plan phase → phase_7
amrmelsayed Oct 29, 2026
cbea2f1
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
c434d95
chore(porch): 329 implement re-iter (iter 2)
amrmelsayed Oct 29, 2026
3a49afe
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
a16e241
chore(porch): 329 advance plan phase → phase_8
amrmelsayed Oct 29, 2026
b399f7e
chore(porch): 329 acknowledge context refresh
amrmelsayed Oct 29, 2026
47b4dfc
[Spec 329][Phase: phase_8] feat: remove the phone number (owner amend…
amrmelsayed Oct 29, 2026
90b2b4e
chore(porch): 329 implement build-complete
amrmelsayed Oct 29, 2026
59419cb
[Spec 329][Phase: phase_8] chore: phase 8 consult outputs (codex COMM…
amrmelsayed Oct 29, 2026
7bf152a
chore(porch): 329 all plan phases complete → review
amrmelsayed Oct 29, 2026
cccbbdb
[Spec 329][Phase: review] docs: review and lessons updated for phase …
amrmelsayed Oct 29, 2026
ab33a01
chore(porch): 329 review build-complete
amrmelsayed Oct 29, 2026
a6809e8
chore(porch): 329 review re-iter (iter 2)
amrmelsayed Oct 29, 2026
cd95ea1
chore(porch): 329 review build-complete
amrmelsayed Oct 29, 2026
3ff3841
chore(porch): 329 pr gate-requested
amrmelsayed Oct 29, 2026
ea95b7c
[Spec 329][Phase: review] docs: extra codex PR review on phase 8 (COM…
amrmelsayed Oct 29, 2026
8289a1b
[Spec 329][Phase: review] fix: security's phase 8 pass (U1 ADD COLUMN…
amrmelsayed Oct 30, 2026
8579b97
fix(whatsapp): drop BuildKit cache mounts so Railway's builder accept…
amrmelsayed Oct 30, 2026
2047dc1
docs(whatsapp): railway.toml records that the staging service exists
amrmelsayed Oct 30, 2026
bda0cd6
Merge pull request #337 from iaser-ai/fix/whatsapp-dockerfile-railway
amrmelsayed Oct 30, 2026
9e6359b
chore(porch): 329 pr gate-approved
amrmelsayed Oct 30, 2026
b1f1b6b
[Spec 329] Review: 0001_api_key applied to staging (owner's output), …
amrmelsayed Oct 30, 2026
b06767d
Merge pull request #331: apps/auth service API keys and the WhatsApp …
amrmelsayed Oct 30, 2026
da568c5
feat(auth): namespace service key prefixes as ansari_<service>_
amrmelsayed Oct 30, 2026
f413d9d
docs(auth): runbook note on the prefix change: rotate wa_ keys, keep …
amrmelsayed Oct 30, 2026
1ccdf04
Merge pull request #338 from iaser-ai/feat/ansari-key-prefixes
amrmelsayed Oct 30, 2026
2a65743
chore(whatsapp): refresh uv.lock to clear the open Dependabot alerts
amrmelsayed Oct 30, 2026
ef9168d
chore(whatsapp): floor certifi at 2026.10.18 with a uv constraint
amrmelsayed Oct 31, 2026
c3f32fc
Merge pull request #341 from iaser-ai/chore/whatsapp-uv-refresh
amrmelsayed Oct 31, 2026
510c9a9
Merge iaser-ai/ansari develop (c3f32fc1) into MachineWisdomAI develop
timeleft-- Nov 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,33 @@ jobs:
- name: Build
run: pnpm exec turbo run build --filter ansari-frontend...

# Python WhatsApp service (spec 321). Not part of the pnpm/turbo graph, so it
# gets its own job. conftest.py supplies mock-mode defaults, so no env or
# repository secrets are needed.
whatsapp:
name: whatsapp (lint, format, test)
runs-on: ubuntu-latest
timeout-minutes: 10
defaults:
run:
working-directory: legacy/whatsapp
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2

- name: Install
run: uv sync --frozen --extra dev

- name: Lint
run: uv run ruff check .

- name: Format check
run: uv run ruff format --check .

- name: Test
run: uv run pytest tests/ -v

gitleaks:
name: gitleaks (secret scan)
runs-on: ubuntu-latest
Expand Down
8 changes: 8 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,12 @@ regexes = [
# check while the test drives sign-up/sign-in against pglite. Literal string,
# not a credential; trips generic-api-key purely on length + the "secret" key.
'''test-secret-at-least-32-characters-long-000''',
# Spec 329 probe scripts, in branch history only: packages/auth/scripts/probes/probe-db.ts
# (commit 90aff8c) and packages/auth/scripts/probes/exchange-lock-probe.ts (commit 427f8fd).
# Synthetic BETTER_AUTH_SECRET and RESEND_API_KEY values, set on process.env so createAuth()
# passes its zod checks for probes run against a throwaway local Postgres. Literal strings,
# not credentials; adjudicated by the security architect, spec 329. Exact full literals,
# never a prefix or a pattern. The tip uses setAuthEnv's placeholders instead.
'''probe-secret-at-least-32-characters-long-00''',
'''re_probe_key_at_least_20_chars''',
]
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,10 @@ You can still target one package directly — `pnpm api lint`, `pnpm frontend we
- **Branch from `develop` and target `develop`** — not `main`. `main` is
production and is only ever fast-forwarded to `develop` during a release (see
[RELEASE.md](RELEASE.md)), so PRs against it can't be merged.
- CI must be green before a PR can merge. `develop` requires all four checks:
- CI must be green before a PR can merge. `develop` requires all five checks:
`api (lint, typecheck, test, build)`, `auth (lint, typecheck, test, build)`,
`frontend (lint, typecheck)`, and `gitleaks (secret scan)`. The
`frontend (lint, typecheck)`, `whatsapp (lint, format, test)`, and
`gitleaks (secret scan)`. The
[Checks](#checks) above are the same tasks, so passing them locally is a good
predictor. If the secret scan fails, see [Secret scanning](#secret-scanning).
- Stage files explicitly (`git add path/to/file`). Please don't use `git add -A`
Expand Down
29 changes: 23 additions & 6 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,16 @@ migration runbook were both proven in real releases on 2026-08-02.
> either half on its own.
> ### Railway service configuration (spec 48 — monorepo layout)
>
> Both services build with the **repo root** as their Root Directory: the pnpm
> workspace needs the root `pnpm-lock.yaml`, and both Dockerfiles now also
> The services build with the **repo root** as their Root Directory: the pnpm
> workspace needs the root `pnpm-lock.yaml`, and the TypeScript Dockerfiles now also
> `COPY packages packages`. Do **not** set Root Directory to the app folder.
>
> | Service | Dockerfile path |
> |---|---|
> | backend | `apps/api/Dockerfile` |
> | frontend (web) | `apps/frontend/Dockerfile.web` |
> | auth | `apps/auth/Dockerfile` |
> | whatsapp | `legacy/whatsapp/Dockerfile` |
>
> **Watch paths** — set these per service, or Railway rebuilds *both* on every push
> (any commit touches the root lockfile):
Expand All @@ -46,17 +47,33 @@ migration runbook were both proven in real releases on 2026-08-02.
> backend: apps/api/** packages/** package.json pnpm-lock.yaml pnpm-workspace.yaml
> frontend: apps/frontend/** packages/** package.json pnpm-lock.yaml pnpm-workspace.yaml
> auth: apps/auth/** packages/** package.json pnpm-lock.yaml pnpm-workspace.yaml
> whatsapp: legacy/whatsapp/**
> ```
>
> `packages/**` is **not optional**. The shared config packages are copied into both
> For backend, frontend and auth, `packages/**` is **not optional**. The shared config packages are copied into those
> images, so a packages-only change alters the built artifact. Omit the pattern and
> that change ships nothing — no rebuild, no deploy, and no error. The image simply
> drifts from the repo.
> drifts from the repo. **whatsapp is the exception:** it is a Python service outside the pnpm workspace, so its image contains nothing from
> `packages/`, the root lockfile or `package.json`; watching them would only rebuild it for changes it does not ship.
>
> **Deploy settings** — backend healthcheck `/api/health` (timeout 300s), frontend
> healthcheck `/`, auth healthcheck `/health` (200 only when the auth database
> healthcheck `/`, whatsapp healthcheck `/`, auth healthcheck `/health` (200 only when the auth database
> answers; timeout 300s); restart ON_FAILURE, max 3 retries.
>
>
> **whatsapp service (spec 321, interim Python import; lives in `legacy/` because `apps/*` is reserved for the
> TypeScript port)** — one listener on `PORT` (8001 by default; the public domain's target port must match).
> Build: repo-root context, `legacy/whatsapp/Dockerfile`. Health check `/`. The Meta callback URL is
> `https://<domain>/whatsapp/v2`, one Meta app per environment. Environment surface (full list in
> `legacy/whatsapp/.env.example`):
> `DEPLOYMENT_TYPE` (required, `staging` or `production`), `BACKEND_SERVER_URL` (apps/api),
> `AUTH_SERVER_URL` and `AUTH_WHATSAPP_API_KEY` (apps/auth, issue #329),
> `META_BUSINESS_PHONE_NUMBER_ID`, `META_ACCESS_TOKEN_FROM_SYS_USER`, `META_ANSARI_APP_SECRET` and
> `META_WEBHOOK_VERIFY_TOKEN` (all four of the same Meta app, all required),
> `SENTRY_DSN`, `WA_MAINTENANCE_MODE`, `WHATSAPP_CHAT_RETENTION_HOURS`, `LOGGING_LEVEL` (unset = `INFO`).
> The service refuses to start if a secret above is missing, or if any `MOCK_*` switch is set outside
> `DEPLOYMENT_TYPE=local`.
>
> **auth service (spec 300)** — one listener: the public domain
> (`auth.askansari.ai`, `auth-staging.askansari.ai`) targets `PORT` (3100); set it as
> a service variable. `backend` reaches it at that domain too (`AUTH_URL`), like any
Expand Down Expand Up @@ -283,7 +300,7 @@ Order proven for migration `0003` on 2026-08-02:
steps: `grant-admin.ts <email>` shows the account (id, email, created_at,
email_verified, role) and grants nothing; `grant-admin.ts <email> --confirm
<id>` grants exactly that account. It never creates an account or touches a
password, and it refuses the system domain. A new admin signs up first; a
password, and it never grants to a system- or noreply-domain address (`--revoke` demotes any account). A new admin signs up first; a
warning on a recent or unverified account means: confirm the person out of
band before `--confirm`. There is no `ADMIN_EMAILS` on `apps/auth` (spec
H-7): the role in the auth database is the only admin truth.
Expand Down
89 changes: 89 additions & 0 deletions apps/api/lib/sentry-scrub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { Event, NodeOptions } from "@sentry/nextjs";

// The client IP travels in x-real-ip (Railway's edge) and x-forwarded-for;
// `sendDefaultPii: false` means Sentry should not receive it. The SDK drops
// these itself only while `userInfo` is off, which Sentry v11 no longer defaults.
const DROPPED_HEADERS = new Set(["authorization", "cookie", "x-real-ip", "x-forwarded-for"]);
// Span attributes that carry the same data. @sentry/nextjs copies headers onto
// the root span (`http.request.header.cookie.<name>`, dashes as underscores),
// masking only sensitive-looking names; Next sets `http.target` to the request
// URL with its query; an outgoing fetch's span carries its query string (the
// search tools put the user's question there); requestdata writes the URL,
// query and body as attributes when spans stream; the client IP has an
// attribute of its own.
const DROPPED_HEADER_ATTRIBUTE =
/^http\.(request\.header\.(authorization|cookie|x_real_ip|x_forwarded_for)|response\.header\.set_cookie)(\.|$)/;
const DROPPED_ATTRIBUTES = new Set([
"url.full",
"url.query",
"http.query",
"http.url",
"http.target",
"http.request.body.data",
"http.client_ip",
"client.address",
]);

function dropAttributes(data: Record<string, unknown> | undefined): void {
if (!data) return;
for (const key of Object.keys(data)) {
if (DROPPED_ATTRIBUTES.has(key) || DROPPED_HEADER_ATTRIBUTE.test(key)) delete data[key];
}
}

/**
* Sentry's request-data integration attaches the in-flight request to every
* event raised while it is handled. Strip what can carry user content or a
* credential: the body (user messages), the query string (`/v2/mcp-complete?q=`
* is the user's question), the Authorization header (the user's JWT),
* cookies and the client IP (its headers, its attribute and
* `user.ip_address`), from the request and from span attributes (issue #333).
* Node lowercases incoming header names, but a header object built elsewhere
* may not, so names are matched case-blind.
*/
export function scrubRequestEvent<E extends Event>(event: E): E {
const request = event.request;
if (request) {
delete request.data;
delete request.cookies;
delete request.query_string;
if (request.url) request.url = request.url.split("?")[0];
if (request.headers) {
for (const name of Object.keys(request.headers)) {
if (DROPPED_HEADERS.has(name.toLowerCase())) delete request.headers[name];
}
}
}
// captureRequestError records the request path with its query.
const nextjs = event.contexts?.nextjs;
if (typeof nextjs?.request_path === "string") nextjs.request_path = nextjs.request_path.split("?")[0];
if (event.user) delete event.user.ip_address;
dropAttributes(event.contexts?.trace?.data);
for (const span of event.spans ?? []) dropAttributes(span.data);
return event;
}

/** The same attribute scrub for each span sent on its own. */
export function scrubSpan<S extends { data?: Record<string, unknown> }>(span: S): S {
dropAttributes(span.data);
return span;
}

/**
* The server's request-privacy options; tests spread exactly these. Transactions
* and spans carry the request too. Breadcrumbs are off: an HTTP breadcrumb
* records an outgoing request's query string, and the search tools put the
* user's question there. `beforeSendSpan` covers the static span lifecycle
* only; under `traceLifecycle: 'stream'` it needs `withStreamedSpan` and the
* streamed `attributes` format (a test pins the lifecycle). Never set
* `dataCollection` partially here: any value switches every category it omits
* to collect-all (user info, bodies, GenAI inputs and outputs, database query
* data).
*/
export const SENTRY_REQUEST_PRIVACY = {
maxBreadcrumbs: 0,
beforeBreadcrumb: () => null,
beforeSend: scrubRequestEvent,
beforeSendTransaction: scrubRequestEvent,
beforeSendSpan: scrubSpan,
} satisfies NodeOptions;
11 changes: 3 additions & 8 deletions apps/api/sentry.server.config.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import * as Sentry from "@sentry/nextjs";

import { SENTRY_REQUEST_PRIVACY } from "./lib/sentry-scrub";

Sentry.init({
dsn: process.env.SENTRY_DSN,
enabled: process.env.NODE_ENV !== "test" && !process.env.VITEST,
environment: process.env.RAILWAY_ENVIRONMENT || process.env.NODE_ENV,
tracesSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1.0,

beforeSend(event) {
// Strip request body data to prevent user messages from leaking to Sentry
if (event.request) {
delete event.request.data;
}
return event;
},
...SENTRY_REQUEST_PRIVACY,
});
16 changes: 16 additions & 0 deletions apps/api/tests/auth/resolve-user.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,22 @@ describe('scenario 9f: an email the app database already holds', () => {
}
});

// Spec 329: the first-use refusal covers the system domain only. A WhatsApp
// user's profile carries apps/auth's other reserved domain, so a tightening
// that refused every reserved address would break WhatsApp here first.
it('a whatsapp-<id>@noreply.askansari.ai profile is accepted, and its row created', async () => {
const { id, jwt } = await signUpDirect(nextEmail('whatsapp'));
const email = `whatsapp-${id}@noreply.askansari.ai`;
await service.client.query(
"update auth.users set email = $1, registered_via = 'whatsapp' where id = $2",
[email, id]
);

expect((await resolveUser(id, jwt)).kind).toBe('user');
expect(await appUser(id)).toMatchObject({ id, email, registered_via: 'whatsapp' });
expect(h.sentry).toEqual([]);
});

it('the email is compared normalized', async () => {
const email = nextEmail('case');
const legacy = await insertLegacyUserRow(app, email);
Expand Down
Loading
Loading