Analysis Process
How this documentation set was produced, for reproducibility and for judging how much to trust it.
Summary
Section titled “Summary”| Date | 2026-07-07 · refreshed 2026-07-17 |
| Source analyzed | jbandassociates/st-integration, branch main, commit 1ce5b3e (“Terms of use, Renewal fixes and July stability release changes”, 2026-07-16). Originally analyzed at f16313c (“Renewal Functionality changes”) |
| Tooling | Claude Code (CLI) with multi-agent orchestration |
| Model | Claude Fable 5 (claude-fable-5, Anthropic Claude 5 family) — same model for the orchestrator and all subagents |
| Method | Static source analysis, then read-only verification of the live AWS environment and production database schema. No code was executed and nothing was modified. |
Artifacts
Section titled “Artifacts”| File | What it is |
|---|---|
| lambda-drift-2026-07-17.xlsx ⬇ | The drift scan, annotated. Column P (Status @ main 1ce5b3e) marks the 13 rows the July release resolved; the other 94 read not re-checked. Note appended to the Summary & Method sheet. |
| lambda-drift-2026-07-13-original.xlsx ⬇ | The unmodified original, kept for provenance. |
The scan was generated 2026-07-13 with Steampipe (aws_jbw) against account 660537473428, comparing deployed Lambda code to three branches: maktix-dev@4b0177e, dev@7a500f1, main@f16313c. One row per function, 107 rows.
It corroborates the corrections log from a third angle: it found no source in any of the three branches for 9 functions, so they were not hiding on a feature branch — they existed only in the AWS console until 1ce5b3e pulled them into git on 2026-07-16. Console first, git second.
Corrections Log
Section titled “Corrections Log”2026-07-17 — first refresh (f16313c → 1ce5b3e)
Section titled “2026-07-17 — first refresh (f16313c → 1ce5b3e)”Re-run against the one release commit that had landed since. Four read-only agents in parallel: the jbw-sam delta, the jbwui delta, a first-pass analysis of jbw-api, and a live AWS re-verification. No code was executed; nothing was modified.
What the original analysis got wrong (as opposed to what merely went stale):
| Claim | Reality | Why it happened |
|---|---|---|
”A second, repo-less API (jb360dealer) — its source lives outside this repo” | The source is jbw-api/, in the repo since 2026-05-20 (cfc5e7a) — seven weeks before the original pass | The analysis scoped itself to three modules named up front and never enumerated the repo’s top level. jbw-api/ was sitting beside them the whole time. |
| Docs covered “the three codebases” | There are four | Same root cause. |
| ”~12 prod functions have no source anywhere” + a follow-up to recover it | 11 were added by 1ce5b3e; the 12th was jb360dealer (above). Every deployed function now has source. | Genuinely true on 07-07; expired nine days later. The framing should have been “no IaC”, which is the durable problem. |
Lambda total 206 (99 dev_*, 3 unprefixed) | 208 (101 dev_*, 5 unprefixed) — and 2 of the extras predate the 07-07 snapshot | Undercount at the time. |
Prod_claims_update_JB runs daily with input bulkUpdate:true | rate(1 hours), input {"agreementid":null,"claimid":null} | Unverified detail carried into the table. |
| Authorizers “confirmed attached on sampled methods” | All 79/79 prod and 80/80 dev — provable in full | Under-claimed; sampling was unnecessary. |
The lesson worth keeping: the wrong claims all came from scoping to what was named rather than enumerating what exists. Three subagents were pointed at three directories and did excellent work inside them; nobody was asked “what else is in this repo?”. The refresh found jbw-api in the first minute, by listing the top level.
What was found that no doc had covered:
jbw-api/in full — including a cross-tenant authorization gap and an RDS IAM token logged at INFO- The Terms-of-Use login gate, with three distinct lockout paths
prodapi_jb360dealerrunning the SAM scaffold (example.Hello::handleRequest) with no env vars and no VPC, while the prod stage routes to itGET /api-docsunauthenticated onJB360IntegrationAPI, invoking the DB-connected dev Lambda- JB360 now writes back into Workiz (
jbwworkizjobdatapush) — previously pull-only - A second SQS enqueuer into the
extractionpipeline (jbwworkiztenantifno) - The July release is committed but not deployed; production leads git, not the reverse
Confirmed still accurate (so the coverage is known): the entire 52-row API route table, the auth quirk, jbw-sam config and build/deploy, both extraction Lambdas’ settings, all 4 event source mappings, CloudFormation staleness, the duplicate schedules, the DLQ gaps, RDS, Cognito, CloudFront, and all 13 S3 buckets. template.yaml is byte-identical across the delta, which is why the route table survived intact.
Corrected same-day — a finding from this very refresh that was itself wrong:
This pass initially reported the trailing space in user/updateterms (jbwui/src/services/userservice.js:9) as a high-severity defect that could stop terms acceptance from ever persisting. That was wrong, and it was briefly published. The space sits at the end of the full URL string, and WHATWG URL parsing — applied by the browser’s XMLHttpRequest.open() to whatever axios passes it — strips leading and trailing spaces. The browser sends /prod/user/updateterms, which matches the real resource (confirmed via aws apigateway get-resources on 18hyg9k8il). Verified: new URL('user/updateterms ', base).pathname → /prod/user/updateterms.
The lesson is the mirror of the jbw-api one: the first mistake came from not looking widely enough, this one from not looking closely enough — reading a string literal and reasoning about what “would” happen instead of testing the runtime that actually consumes it. Both were caught by checking rather than concluding. Static reading of source is a hypothesis, not a finding.
The other half of that finding stands: handleTermsAccept swallows write failures and navigates anyway (SignIn.js:249-256), so any genuine failure is invisible.
Still unresolved:
- Do
jbw-adminusers havetblDealerRegistrationrows? If not, the terms gate locks admins out. Not answerable read-only from outside the account: the prod DB (jbw-st-integration) isPubliclyAccessible: falseinsidevpc-0541449e6318d65ff, with no public endpoint. Needs a bastion, a VPC-attached client, or someone with an existing tunnel. - Which
dev_*functions are new since 07-07 —list-functionsexposes no creation date; needs CloudTraillookup-events. - Repo-source vs deployed
CodeSha256equivalence — needs a build toolchain per function.
Method
Section titled “Method”The analysis ran as one orchestrating session plus three read-only explorer subagents in parallel, one per subproject:
| Subagent scope | What it read | Effort |
|---|---|---|
extraction/ | pom.xml, all Java source (src/main/java/...), application.yml, HELP.md | ~71k tokens, 25 tool calls, ~2.5 min |
jbw-sam/ | template.yaml (all ~1,750 lines), samconfig.toml, events/, Lambda handler sources under src/ | ~100k tokens, 33 tool calls, ~6.5 min |
jbwui/ | package.json, env files, router, AuthContext, all src/services/*, pages/components/layouts | ~106k tokens, 68 tool calls, ~4 min |
Each subagent was prompted to return structured factual notes with file paths for every claim (not prose), covering:
- purpose and tech stack
- entry points
- external systems
- configuration
- data flow
- build / run / deploy
- error handling
The orchestrator then cross-referenced the three reports (e.g. matching the getTenantInfo SQS hand-off in jbw-sam to the extraction Lambda’s SQS trigger, and jbwui service endpoints to jbw-sam API routes) and wrote the docs.
Supplementary inputs gathered by the orchestrator directly: repo git log (release cadence), top-level directory structure.
Conventions Applied
Section titled “Conventions Applied”- Secrets masked: hardcoded credentials found in source (ServiceTitan app key, JBW API token, Workiz token, Cognito pool IDs, AES key, dev DB password) are referenced by location in these docs but their values are not reproduced.
- Every architectural claim traces to a file path in the repo; the code-reference docs are the path index.
- Discovered defects (template indentation bug, name-mismatch
!Refs, route collision, injection-prone SQL, logged tokens) are reported as-found under “Caveats / Known Issues” in each module doc — none were fixed as part of this analysis.
Live AWS & Database Verification
Section titled “Live AWS & Database Verification”After the source-only pass, the deployed environment was verified with read-only AWS CLI calls (list/get/describe only; no drift-detection run, nothing modified) against account 660537473428, covering:
- Lambda inventory + event source mappings
- EventBridge schedules
- SQS queue attributes
- API Gateway authorizers and sampled method auth
- Cognito pools
- CloudFormation stacks
- S3 / CloudFront
- EC2 network resources (VPCs, subnets, security groups, NAT)
- RDS instances, proxies, proxy targets
The production database was inspected read-only (information_schema tables/views/routine definitions only — no data rows queried beyond counts). Historical context from the January 2024 deployment notes went into aws/deployment-history.md. Results: the aws/ section.
Known Limitations
Section titled “Known Limitations”- The source docs (01–04) are static analysis. Runtime facts live in aws/; the account has drifted far from the repo (CloudFormation last ran May 2024), so docs 01–04 describe the code and
aws/describes reality. - Where the notes/code and the live account conflicted, the live account won (e.g. prod runs in the “JBW Network” VPC, not the default VPC; the prod DB instance is
jbw-st-integration; there is nojbw_workiz_dataSyncprocedure). - CloudWatch metrics/error rates and SES sending state were not reviewed.
- In docs 01–04, database details are inferred from entity classes and SQL in handlers; the verified schema lives in aws/database.md.
- Coverage of the ~72
jbwuicomponents and 44 non-templatedjbw-samsource dirs is at the responsibility level, not line-by-line. - The docs describe commit
1ce5b3e; the repo evolves by quarterly release commits, so re-run the analysis after each release. - Git is not the deployment record. Code reaches the AWS console first and the repo second — the July 2026 release is committed but not deployed, and some of its functions were console-pushed before being committed. A commit hash tells you what the team wrote, not what is running. Only the
aws/pages speak to the latter.
Reproducing / Refreshing
Section titled “Reproducing / Refreshing”- Pull latest
maininst-integration. - Enumerate the repo’s top level first (
git ls-tree --name-only main:) and reconcile it against the module pages before scoping anything. The 2026-07-17 refresh exists largely because the first pass skipped this and missedjbw-api/— see the corrections log. - Launch one read-only explorer subagent per top-level module, with the same reporting prompt as above: structured factual notes, a file path behind every claim, secrets by location only.
- Run a fourth agent for the live AWS re-verification (read-only
list/get/describeonly). Have it re-test the specific claims on theaws/pages rather than re-inventory from scratch, and always ask whether the latest release is actually deployed — the answer has been “no” once already. - Cross-reference the reports, update the module docs and code references, and refresh the commit hash and date in this file and
README.md. - Add a dated entry to the corrections log distinguishing what went stale from what was wrong. The second kind is the one worth learning from.