Skip to content

Analysis Process

How this documentation set was produced, for reproducibility and for judging how much to trust it.

Date2026-07-07 · refreshed 2026-07-17
Source analyzedjbandassociates/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”)
ToolingClaude Code (CLI) with multi-agent orchestration
ModelClaude Fable 5 (claude-fable-5, Anthropic Claude 5 family) — same model for the orchestrator and all subagents
MethodStatic source analysis, then read-only verification of the live AWS environment and production database schema. No code was executed and nothing was modified.
FileWhat it is
lambda-drift-2026-07-17.xlsxThe 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.xlsxThe 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.

2026-07-17 — first refresh (f16313c1ce5b3e)

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):

ClaimRealityWhy 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 passThe 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 fourSame root cause.
”~12 prod functions have no source anywhere” + a follow-up to recover it11 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 snapshotUndercount at the time.
Prod_claims_update_JB runs daily with input bulkUpdate:truerate(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 fullUnder-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_jb360dealer running the SAM scaffold (example.Hello::handleRequest) with no env vars and no VPC, while the prod stage routes to it
  • GET /api-docs unauthenticated on JB360IntegrationAPI, invoking the DB-connected dev Lambda
  • JB360 now writes back into Workiz (jbwworkizjobdatapush) — previously pull-only
  • A second SQS enqueuer into the extraction pipeline (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-admin users have tblDealerRegistration rows? If not, the terms gate locks admins out. Not answerable read-only from outside the account: the prod DB (jbw-st-integration) is PubliclyAccessible: false inside vpc-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-functions exposes no creation date; needs CloudTrail lookup-events.
  • Repo-source vs deployed CodeSha256 equivalence — needs a build toolchain per function.

The analysis ran as one orchestrating session plus three read-only explorer subagents in parallel, one per subproject:

Subagent scopeWhat it readEffort
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.

  • 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.

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.

  • 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 no jbw_workiz_dataSync procedure).
  • 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 jbwui components and 44 non-templated jbw-sam source 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.
  1. Pull latest main in st-integration.
  2. 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 missed jbw-api/ — see the corrections log.
  3. 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.
  4. Run a fourth agent for the live AWS re-verification (read-only list/get/describe only). Have it re-test the specific claims on the aws/ pages rather than re-inventory from scratch, and always ask whether the latest release is actually deployed — the answer has been “no” once already.
  5. Cross-reference the reports, update the module docs and code references, and refresh the commit hash and date in this file and README.md.
  6. 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.