Public record
Software health reportschema 0.27.0 · metrics 1.13.0 · 2026-07-23 20:14 UTC

samsmithyeah / tapsmith

Playwright-level reliability for mobile app testing. Rust core + TypeScript SDK + Android agent.

TypeScript · RustApache-2.0★ 8 stars⑂ 0 forkssince Mar 2026View on GitHub ↗

samsmithyeah/tapsmith holds a health index of 61 out of 100, placing it in the Moderate band. It scores highest on Vitality (86/100) and lowest on Community & Adoption (40/100). It was last updated 4 days ago. A single contributor accounts for most of its recent work.

61
overall / 100
Moderate

Software health index

Metrics are grouped into weighted categories on one standardized 1–100 scale. Overall starts as their weighted mean; when public evidence triggers the High-Risk Jurisdiction Policy, the rating is adjusted and receives an At risk ceiling of 49. AI Readiness sits outside the overall score.

61
Excellent85-100Exemplary; meets essentially all checked criteria
Good70-84Healthy; minor gaps
Moderate50-69Acceptable with notable gaps; review recommended
At risk30-49Significant weaknesses; adoption warrants caution
Critical1-29Severe problems (abandoned, single-maintainer, no hygiene)
VitalityCommunity &AdoptionSustainability &GovernanceEngineeringQualitySecurityAI Readiness

Score profile

Each axis is a category. The shape matters more than the average — a healthy subject fills the whole shape, while a spike-and-crater profile means strength in one dimension is masking risk in another.

Ownership

Sam SmithPersonal account
3 followers12 public repossince Oct 2016@redbadger

This repository is owned by a personal account. A single-owner project carries more continuity risk than an organization-backed one.

Package ecosystems

RegistryPackageVersionDownloads / moVersionsLast publishTags
npmwebsitepoints to another repo — not scored0.1.11,19124817 days agoscrapingweb
npmtapsmith0.4.01,569175 days agomobiletestingandroidiosautomationui-testing
npm@tapsmith/agent-android0.4.03,128145 days ago
npm@tapsmith/core-linux-x640.4.02,617165 days ago
npm@tapsmith/core-darwin-x640.4.01,569165 days ago
npm@tapsmith/core-linux-arm640.4.01,475165 days ago
npm@tapsmith/core-darwin-arm640.4.02,231165 days ago
npm@tapsmith/agent-ios-simulator-x640.4.01,274155 days ago

Metrics by category

Vitality

Is the project alive — is code being written and are releases shipping?

86Excellent · 22% of overall
How it's scored
36/36Push recency — last push 4 days ago
12.5/36Commit cadence — 18/52 weeks with commits
18/18Commit volume — 227 commits in the last year
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
Inputs used
commits_last_year227
human_commit_share0.97
days_since_last_push4
active_weeks_last_year18

Release discipline

100Excellent
How it's scored
27/27Ships releases — 16 releases published
36/36Release recency — latest release 5 days ago
27/27Release cadence — a release every ~1.8 days
0/10OpenSSF Scorecard: Signed-Releases — no data
Inputs used
releases_count16
latest_release_tagv0.4.0
releases_from_tagsno
days_since_latest_release5
mean_days_between_releases1.8
Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.

Community & Adoption

Does the project have users, downloads, attention, and a welcoming setup for contributors?

40At risk · 18% of overall
How it's scored
13.7/60Stars — 8 stars
0/25Forks — 0 forks
0/15Watchers — 0 watchers
Inputs used
forks0
stars8
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
How it's scored
22.5/22.5README
22.5/22.5License — recognized license (Apache-2.0)
0/18CONTRIBUTING guide
0/13.5Code of conduct
0/7.2Issue template
0/6.3PR template
Inputs used
has_readmeyes
has_licenseyes
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno
How it's scored
55.2/80Monthly downloads — 13,863 downloads/month across npm
0/20Registry dependents — not reported by this ecosystem
Inputs used
packagestapsmith, @tapsmith/agent-android, @tapsmith/core-linux-x64, @tapsmith/core-darwin-x64, @tapsmith/core-linux-arm64, @tapsmith/core-darwin-arm64, @tapsmith/agent-ios-simulator-x64
dependents
ecosystemsnpm
total_downloads
monthly_downloads13,863
Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.

Sustainability & Governance

Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?

44At risk · 24% of overall
How it's scored
9/54Bus factor — 1 contributor(s) cover half of all commits
0/22.5Commit distribution — top contributor authored 100% of commits
1.4/13.5Contributor breadth — 1 contributors
3/10OpenSSF Scorecard: Contributors — project has 1 contributing companies or organizations -- score normalized to 3
Inputs used
bus_factor1
contributors_sampled1
top_contributor_share1
How it's scored
0/46.8Issue resolution — 0% of issues closed
36.6/38.3PR acceptance — 178/186 decided PRs merged
0/15OpenSSF Scorecard: Code-Review — Found 0/27 approved changesets -- score normalized to 0
Inputs used
merged_prs178
open_issues2
closed_issues0
issue_closed_ratio0
closed_unmerged_prs8
How it's scored
10/30Ownership backing — personal (user) account
0/20Verified domain — not applicable to user accounts
4.3/25Owner reach — 3 followers of samsmithyeah
20.1/25Track record — 12 public repos, account ~9 yr old
Inputs used
followers3
owner_typeUser
is_verified
owner_loginsamsmithyeah
public_repos12
account_age_days3,580
Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.
How it's scored
25/25Published & resolvable — 7 package(s) on npm
35/35Publish recency — latest publish 5 days ago
20/20Version history — 17 published versions
20/20Not deprecated — active, not deprecated or yanked
Inputs used
packagestapsmith, @tapsmith/agent-android, @tapsmith/core-linux-x64, @tapsmith/core-darwin-x64, @tapsmith/core-linux-arm64, @tapsmith/core-darwin-arm64, @tapsmith/agent-ios-simulator-x64
ecosystemsnpm
any_deprecatedno
min_days_since_publish5

Engineering Quality

Are baseline engineering and documentation practices in place?

80Good · 20% of overall
How it's scored
24/24CI workflows — 11 workflow(s)
24/24Tests present
16/16Linter config — eslint.config.mjs
0/9.6Pre-commit hooks
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 30 out of 30 merged PRs checked by a CI test -- score normalized to 10
Inputs used
has_ciyes
has_testsyes
has_editorconfigno
has_linter_configyes
has_precommit_configno
How it's scored
30/30README
25/25Documentation directory
0/15Documentation / homepage site
10/10Repository description
0/10Topics
10/10Wiki
Inputs used
topics
has_wikiyes
homepage
has_readmeyes
has_docs_diryes
has_descriptionyes

Security

Are visible security and supply-chain practices strong, without unresolved high-risk jurisdiction exposure?

50Moderate · 16% of overall
How it's scored
6.8/7.5Binary-Artifacts — binaries present in source code
2.2/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 30 out of 30 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/27 approved changesets -- score normalized to 0
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5License — license file detected
7.5/7.5Maintained — 30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
1.5/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 3
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — no data
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
0/7.5Vulnerabilities — 92 existing vulnerabilities detected
Inputs used
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate4
Excluded from scoring (no data or not applicable): signed_releases. Remaining weights renormalized.
How it's scored
35/35Direct dependencies free of known advisories — no direct dependency carries a known advisory
13.2/25Indirect dependencies free of known advisories — 1 affected: @hono/node-server 1.19.14 (moderate 5.9)
40/40No advisories left outstanding — no advisory has been public longer than 90 days
Inputs used
sourceosv
advisories1
affected_packages1
assessed_packages203
unassessed_packages0
affected_by_severitymoderate 1
direct_affected_packages0
Matched the npm:tapsmith@0.4.0 runtime dependency closure — what installing the published package pulls in — 203 packages. Reachability is not analyzed.

AI Readiness

How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score.

81Good · 0% of overall
How it's scored
45/45Agent instructions — CLAUDE.md, docs/agents.md
0/15Machine-readable docs (llms.txt)
40/40Legible commit history — 95 of 97 human commits state their intent (structured subject or explanatory body)
Inputs used
has_llms_txtno
legible_history_share0.979
agent_instruction_filesCLAUDE.md, docs/agents.md
agent_instruction_max_bytes8,640
How it's scored
12.6/18One-command bootstrap — agent/app/build.gradle.kts, agent/build.gradle.kts, packages/tapsmith-core/Cargo.toml (toolchain convention, no task runner)
22/22Automated tests
11/11Lint / format config — eslint.config.mjs
11/11Static type checking — packages/tapsmith/tsconfig.json, test-app/tsconfig.json, website/tsconfig.json
10/10Reproducible environment — lockfile
10/10Demonstrated agent practice — 87 of the last 100 commits agent-authored or agent-credited
0/8Automated maintenance — no automated dependency updates observed
3/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 3
Inputs used
has_nixno
has_testsyes
lockfilesCargo.lock, package-lock.json
has_dockerfileno
typed_languageyes
bootstrap_files
has_devcontainerno
has_linter_configyes
typecheck_configspackages/tapsmith/tsconfig.json, test-app/tsconfig.json, website/tsconfig.json
agent_commit_share0.87
toolchain_manifestsagent/app/build.gradle.kts, agent/build.gradle.kts, packages/tapsmith-core/Cargo.toml
dependency_bot_commit_share0
How it's scored
45/45Type-checkable code — TypeScript (statically typed)
52.4/55Manageable file sizes — 18/388 source files over 60KB
Inputs used
primary_languageTypeScript
largest_source_bytes332,289
source_files_sampled388
oversized_source_files18
How it's scored
40/40API schema (OpenAPI/GraphQL/proto) — packages/tapsmith-core/vendor/mitmproxy_ipc.proto, proto/tapsmith.proto
20/20MCP server
0/40Runnable examples
Inputs used
example_dirs
has_mcp_signalyes
api_schema_filespackages/tapsmith-core/vendor/mitmproxy_ipc.proto, proto/tapsmith.proto

Key facts

8GitHub stars
1contributors
227commits, last 12 months
4days since last push
16releases
1bus factor
2open issues
Maven, npmpackage ecosystems

Data collection warnings

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • npm package 'website' points at a different repository (https://github.com/akoenig/node-website); excluded from ecosystem scoring
  • Could not fetch crates package 'tapsmith-core' from its registry
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

More detail

OpenSSF Scorecard 4.0 / 10
4.0aggregate

Independent, tool-agnostic security assessment from the open-source OpenSSF Scorecard. Each check rewards a security practice, not a specific vendor's tool. Checks Scorecard could not determine are marked n/a and excluded from the security score (never counted as zero).Scorecard v5.5.0 · 2026-07-23 20:14 UTC

9Binary-Artifactsbinaries present in source code
3Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests30 out of 30 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/27 approved changesets -- score normalized to 0
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
3Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 3
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
n/aSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities92 existing vulnerabilities detected
Direct dependencies 74
RegistryPackageVersion constraintManifest
npmtapsmithfile:../packages/tapsmithe2e/package.json
npm@expo/vector-icons^15.0.2test-app/package.json
npm@react-native-async-storage/async-storage^2.2.0test-app/package.json
npmexpo~55.0.6test-app/package.json
npmexpo-camera~55.0.9test-app/package.json
npmexpo-clipboard~55.0.8test-app/package.json
npmexpo-constants~55.0.7test-app/package.json
npmexpo-linking~55.0.7test-app/package.json
npmexpo-location~55.1.2test-app/package.json
npmexpo-router~55.0.5test-app/package.json
npmexpo-secure-store~55.0.14test-app/package.json
npmexpo-status-bar~55.0.4test-app/package.json
npmreact19.2.0test-app/package.json
npmreact-native0.83.2test-app/package.json
npmreact-native-safe-area-context~5.6.2test-app/package.json
npmreact-native-screens~4.23.0test-app/package.json
npmreact-native-webview^13.12.5test-app/package.json
npm@astrojs/starlight^0.39.2website/package.json
npm@tailwindcss/vite^4.3.0website/package.json
npmastro^6.3.1website/package.json
npmsharp^0.34.5website/package.json
npmstarlight-image-zoom^0.14.2website/package.json
npmstarlight-links-validator^0.24.0website/package.json
npmtailwindcss^4.3.0website/package.json
crates.iotonic0.12packages/tapsmith-core/Cargo.toml
crates.ioprost0.13packages/tapsmith-core/Cargo.toml
crates.iotokio1packages/tapsmith-core/Cargo.toml
crates.iotokio-stream0.1packages/tapsmith-core/Cargo.toml
crates.iohyper1packages/tapsmith-core/Cargo.toml
crates.iohyper-util0.1packages/tapsmith-core/Cargo.toml
crates.iohttp-body-util0.1packages/tapsmith-core/Cargo.toml
crates.ioh20.4packages/tapsmith-core/Cargo.toml
crates.iohttp1packages/tapsmith-core/Cargo.toml
crates.iobytes1packages/tapsmith-core/Cargo.toml
crates.ioserde1packages/tapsmith-core/Cargo.toml
crates.ioserde_json1packages/tapsmith-core/Cargo.toml
crates.ioanyhow1packages/tapsmith-core/Cargo.toml
crates.iothiserror2packages/tapsmith-core/Cargo.toml
crates.iotracing0.1packages/tapsmith-core/Cargo.toml
crates.iotracing-subscriber0.3packages/tapsmith-core/Cargo.toml
crates.iouuid1packages/tapsmith-core/Cargo.toml
crates.iobase640.22packages/tapsmith-core/Cargo.toml
crates.iorcgen0.13packages/tapsmith-core/Cargo.toml
crates.iox509-parser0.16packages/tapsmith-core/Cargo.toml
crates.iomd-50.10packages/tapsmith-core/Cargo.toml
crates.iotime0.3packages/tapsmith-core/Cargo.toml
crates.iotokio-rustls0.26packages/tapsmith-core/Cargo.toml
crates.iorustls0.23packages/tapsmith-core/Cargo.toml
crates.iorustls-pemfile2packages/tapsmith-core/Cargo.toml
crates.iowebpki-roots0.26packages/tapsmith-core/Cargo.toml
crates.iodirs6.0.0packages/tapsmith-core/Cargo.toml
crates.ioasync-trait0.1packages/tapsmith-core/Cargo.toml
crates.ioregex1packages/tapsmith-core/Cargo.toml
crates.iourl2packages/tapsmith-core/Cargo.toml
crates.iocrc32fast1.4packages/tapsmith-core/Cargo.toml
crates.ioplist1.7packages/tapsmith-core/Cargo.toml
crates.iotempfile3packages/tapsmith-core/Cargo.toml
crates.iolibc0.2packages/tapsmith-core/Cargo.toml
npm@grpc/grpc-js^1.12.0packages/tapsmith/package.json
npm@grpc/proto-loader^0.7.13packages/tapsmith/package.json
npm@modelcontextprotocol/sdk^1.29.0packages/tapsmith/package.json
npmbplist-creator^0.1.1packages/tapsmith/package.json
npmbplist-parser^0.3.2packages/tapsmith/package.json
npmchokidar^4.0.3packages/tapsmith/package.json
npmenquirer^2.4.1packages/tapsmith/package.json
npmfflate^0.8.2packages/tapsmith/package.json
npmfiglet^1.11.0packages/tapsmith/package.json
npmglob^11.0.0packages/tapsmith/package.json
npmminimatch^10.2.4packages/tapsmith/package.json
npmopen^10.2.0packages/tapsmith/package.json
npmproper-lockfile^4.1.2packages/tapsmith/package.json
npmtsx^4.21.0packages/tapsmith/package.json
npmws^8.20.0packages/tapsmith/package.json
npmzod^4.3.6packages/tapsmith/package.json
All dependencies not collected

The resolved dependency set could not be collected for this report: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Dependency advisories 1

Installing npm:tapsmith@0.4.0 pulls in 203 packages, direct and transitive: 1 carry known advisories, of which 0 are direct dependencies.

PackageVersionRelationSeverityAdvisoriesFixed in
@hono/node-server1.19.14indirectmoderate12.0.5

An advisory means the version recorded in the dependency graph falls inside an advisory’s affected range. Reachability is not analysed, and the graph includes development and test pins — a finding may concern tooling rather than shipped software.

Raw JSON report machine-readable
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 13225,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "C": 4483,
        "CSS": 5540,
        "HTML": 6095,
        "Rust": 1104673,
        "Astro": 50193,
        "Shell": 6821,
        "Swift": 300489,
        "Kotlin": 137285,
        "JavaScript": 171652,
        "TypeScript": 3346801,
        "Objective-C": 13039
      },
      "pushed_at": "2026-07-18T21:22:45Z",
      "created_at": "2026-03-13T22:42:03Z",
      "owner_type": "User",
      "updated_at": "2026-07-19T22:06:08Z",
      "description": "Playwright-level reliability for mobile app testing. Rust core + TypeScript SDK + Android agent.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "main",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "TypeScript",
      "significant_languages": [
        "TypeScript",
        "Rust"
      ]
    },
    "owner": {
      "blog": null,
      "name": "Sam Smith",
      "type": "User",
      "login": "samsmithyeah",
      "company": "@redbadger ",
      "location": "London",
      "followers": 3,
      "avatar_url": "https://avatars.githubusercontent.com/u/22592849?v=4",
      "created_at": "2016-10-03T13:11:19Z",
      "is_verified": null,
      "public_repos": 12,
      "account_age_days": 3580
    },
    "license": {
      "state": "standard",
      "spdx_id": "Apache-2.0",
      "raw_spdx": "Apache-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-07-18T12:36:24Z"
        },
        {
          "tag": "v0.3.5",
          "kind": "patch",
          "published_at": "2026-07-03T16:36:50Z"
        },
        {
          "tag": "v0.3.4",
          "kind": "patch",
          "published_at": "2026-07-02T14:47:41Z"
        },
        {
          "tag": "v0.3.3",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:47Z"
        },
        {
          "tag": "v0.3.2",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:45Z"
        },
        {
          "tag": "v0.3.1",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:43Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-07-02T10:40:42Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-07-02T10:40:40Z"
        },
        {
          "tag": "v0.1.8",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:38Z"
        },
        {
          "tag": "v0.1.7",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:37Z"
        },
        {
          "tag": "v0.1.6",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:35Z"
        },
        {
          "tag": "v0.1.5",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:34Z"
        },
        {
          "tag": "v0.1.4",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:32Z"
        },
        {
          "tag": "v0.1.3",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:30Z"
        },
        {
          "tag": "v0.1.2",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:29Z"
        },
        {
          "tag": "v0.1.1",
          "kind": "patch",
          "published_at": "2026-07-02T10:40:27Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "d7293e51ae96a8646f1b3e9d1918f106a39391ab",
          "body": "Co-authored-by: tapsmith-release[bot] <tapsmith-release@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Release v0.4.0 (#192)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-07-18T12:30:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cf3febd68ef76ab147303d9657a495c68f7a00b0",
          "body": null,
          "is_bot": false,
          "headline": "Refresh website/docs screenshots and add click-to-enlarge (#191)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-18T12:07:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c042205fc4da6db2107bd06cd0add57edaa34984",
          "body": "…, and agents (#190)\n\n* Harden E2E reliability across SDK, daemon, and on-device agents\n\nFixes for every root-caused CI flake cluster from the July sweep:\n\nAndroid agent:\n- Unwrap InvocationTargetException in ElementFinder.nodeInfoFor so a\n  StaleObjectException thrown mid-re-render hits the existin\n[…]\n=22).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015UnUDsBKe7PEyEVCmUg4Ei\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Make E2E CI resilient: fix every root-caused flake across SDK, daemon…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-18T06:50:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "585ba74fa0db9407eda2bf458cd5e1b6e4d17d7d",
          "body": "…rst (PILOT-288) (#189)\n\n* Bound and retry iOS WebView connection setup; probe newest targets first (PILOT-288)\n\ndevice.webview() on iOS could hang until the caller's test timeout\n(~20% of local webview tests) because connection setup had unbounded\nsteps: the webinspectord Unix-socket connect had no\n[…]\nlure.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015At8QshVtAS7i4NN6B2gbZ\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Bound and retry iOS WebView connection setup; probe newest targets fi…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-15T13:06:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7046962c8d58122edc2d0427a00ce5d74c0c8155",
          "body": "* Extend strict mode to WebView locators (PILOT-227)\n\nwebview.getBy*/locator() locators now enforce Playwright-style strict\nmode instead of silently acting on the first DOM match:\n\n- Finder scripts return the full match array; actions, single-element\n  queries, and positive assertions throw a Strict\n[…]\nctor.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_016hyU9cqWGuWd2mwELUHi7n\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Extend strict mode to WebView locators (PILOT-227) (#188)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-14T18:00:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9a290bddf76f2eb16a7ba837cc94c6c27871cb36",
          "body": "…284) (#183)\n\n* Dismiss the Android soft keyboard with BACK instead of ESCAPE (PILOT-284)\n\n`hideKeyboard` on Android sent `input keyevent KEYCODE_ESCAPE`, which is a\nno-op for the IME on most apps (confirmed on Flutter's demo_app): the\nkeyboard stayed up and `hideKeyboard()` silently did nothing.\n\nS\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_011H2L6cxRt27L26reDEw7Fj\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Dismiss the Android soft keyboard with BACK instead of ESCAPE (PILOT-…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-14T13:25:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4cb98b475c4315682168d9faa40193cef9b89537",
          "body": "* Include beforeAll actions in packaged test traces, not just the UI live stream\n\nbeforeAll hooks run against a standalone trace collector, and their events\nwere only ever forwarded to each test via the UI-mode event callback —\nreplayBeforeAllEvents bailed out when no callback was set, so in headles\n[…]\ndisk.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_012ovDzvjQfgk6ExfKKEv8eS\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Include beforeAll and afterAll actions in packaged test traces (#175)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-14T10:41:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e9639ce5d58c5e7f63ddf65c0ee5f490600f974e",
          "body": "…s attribution (#186)\n\n* UI mode: keep a finished test's status and trace when afterAll re-tags attribution\n\nWhen a suite has afterAll hooks and tracing is on, the runner re-fires\nonTestStart for the last test that ran so the hooks' trace events get\nattributed to it. The UI treated that re-tag as a \n[…]\n shifted hook events; the in-flight selection\nfallback converts the same way.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "UI mode: keep a finished test's status and trace when afterAll re-tag…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-13T10:35:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "572e29a4f7fde32d8d1223a072db9e43d3762f2f",
          "body": "…ure (#185)\n\n* Guide users off Google Play AVD images that silently break HTTPS capture\n\nGoogle Play (google_apis_playstore) system images — the ones Android\nStudio preselects — are production builds where adbd cannot restart as\nroot, so Tapsmith can neither install its CA cert into the system trust\n[…]\ntion.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NsFtffoMJeYJAemGogNK2F\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Guide users off Google Play AVD images that silently break HTTPS capt…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-13T10:02:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "422a71f6c2f53e61848c50e18bf3b792b412ddd1",
          "body": "* Record no assertion bounds when the element is hidden or gone\n\nThe trace viewer draws an assertion's bounds over the \"after\" screenshot\n(the next action's before-shot). Bounds were recorded via findElement,\nwhich matches present-but-invisible elements with a real frame, and fell\nback to bounds cap\n[…]\n#177.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01QdEqn6uUQW1wBoF4aVDEZh\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Record no assertion bounds when the element is hidden or gone (#177)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-09T16:03:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fd5a5a1c034a190072d2a86e405fe217ffa537b0",
          "body": "…ession-wide suite status tool (#184)\n\n* Keep long MCP test runs alive with progress and add a session-wide suite status tool (PILOT-285, PILOT-286)\n\ntapsmith_run_tests now emits notifications/progress every 10s while a run\nexecutes (when the client supplies a progressToken), reporting live pass/fai\n[…]\nment.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NTZXAd66UUE9CZdedX1N7o\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Keep long MCP test runs alive with progress notifications and add a s…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-09T15:50:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f451fec9ce7e9fb2140bbc8aa9d867bc47dcd8a2",
          "body": "…delivered (#178)\n\nWarm in-process deep-link delivery (PILOT-249) verifies receipt by requiring\nthe a11y hierarchy to change from its pre-open state within 5s. A per-test\nsoft reset like __reset?path=/toggles that lands back on the screen the app\nis already showing renders an identical hierarchy (an\n[…]\nps it from intercepting taps; no e2e selector\nmatches the marker text.\n\n\nClaude-Session: https://claude.ai/code/session_01WxFaJxfLUgYHjYQ3kjcT83\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Render a reset-epoch marker so warm same-screen iOS resets verify as …",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-09T14:14:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6ac07cab93d55debce014c9ec590fdf68b135b5e",
          "body": "…179)\n\nEach of the 5 macOS shard jobs was paying 1.7-4 min for an uncached\n`npm ci` in packages/tapsmith (setup-node had no npm cache here, unlike\nthe merge-reports job) plus 1.3-3 min blocking on simulator boot before\nany npm work started.\n\n- setup-node now caches npm keyed on both the SDK and e2e \n[…]\n> 120s since a cold boot now\n  overlaps several minutes of other work.\n\n\nClaude-Session: https://claude.ai/code/session_01WxFaJxfLUgYHjYQ3kjcT83\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Speed up iOS E2E shard setup: cache npm and overlap simulator boot (#…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-09T14:13:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a27564ea6a7774496e03d2bae69af56eb46a7a34",
          "body": "…OT-283) (#181)\n\n* Make scrollIntoView a reliable no-op on already-visible elements (PILOT-283)\n\nscrollIntoView() swiped whenever a probe tick failed to report the target,\neven when the tick carried no information: a transient agent-command\ntimeout, a stale mid-update snapshot, or an accessibility t\n[…]\ntion.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01FdmGZerbUPLgvbbBhHc3xF\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Make scrollIntoView a reliable no-op on already-visible elements (PIL…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-09T14:12:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8ba701e207ceef44222319e8f18a623e1b339490",
          "body": "…182)\n\n* Ride out transient agent-connection drops in test runs (PILOT-282)\n\nA transient agent-connection drop takes a few seconds to clear, but every\nretry layer in the test-run path fired immediately: ensureSessionReady's\nverify → recover → verify cycle, the file-level recovery, and the worker-\nin\n[…]\nlback\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01FdmGZerbUPLgvbbBhHc3xF\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Ride out transient agent-connection drops in test runs (PILOT-282) (#…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-09T12:10:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "069547fac7214a91e4b71bea402db842a5ab4197",
          "body": "* Add element pick mode to the live device mirror in UI mode\n\nThe locator picker previously worked only on trace screenshots. This\nextends it to the live device mirror: a pick button in the mirror\nheader enables hover highlighting and click-to-pick against the live\naccessibility hierarchy, feeding t\n[…]\ntion.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NgajBqc9smtYYhq8m78qWb\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add element pick mode to the live device mirror in UI mode (#180)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-08T21:03:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f1f69e8498321da23d39863d0b40fd5cb12f2293",
          "body": "…T-253) (#176)\n\n* Surface UI/watch startup failures instead of silently exiting 1 (PILOT-253)\n\nStartup errors escaping main() in UI/watch mode died silently: the\nsequential finally block scheduled setTimeout(process.exit, 0), and\nmain().catch's first statement is a dynamic import of dispatcher.js,\ns\n[…]\naths.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_012QaT7kR3ze2H9L5rMCpf3T\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Surface UI/watch startup failures instead of silently exiting 1 (PILO…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-07T15:22:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "41b4faa42631d982d991798b3afddf0d24cd7bb5",
          "body": "… file boundaries (PILOT-249) (#174)\n\n* Try warm in-process delivery before cold relaunch for iOS simulator deep links (PILOT-249)\n\nOn simulators every openDeepLink — including the per-test soft reset —\npaid a terminate -> simctl openurl cold relaunch (~14-22s on CI). The\nwarm path now tries the phy\n[…]\ndict.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01JBip7ssKNvp64DYk8skLAc\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Warm in-process deep-link delivery on iOS simulators, bounded by cold…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-07T00:11:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "feb02086707eefa406f9a2bb8ec06c4290988aaf",
          "body": "The project doesn't label PRs, so GitHub's category grouping only ever produces\na lone \"Other Changes\" bucket. Flatten each release's notes into a plain list of\nits PRs in website/scripts/sync-releases.mjs:\n\n- drop the `<!-- Release notes generated ... -->` HTML comment GitHub prepends\n  when .githu\n[…]\nreated \"Release vX.Y.Z\" PR still stays out of the notes.\n\n\nClaude-Session: https://claude.ai/code/session_01J9XXZdm3V42fjmDh7tH8MK\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Render website changelog as flat bullet lists (no categorisation) (#170)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-06T21:46:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "170ed7fd7d4d727bf3ebd61703ceeda5180aea56",
          "body": "Co-authored-by: tapsmith-release[bot] <tapsmith-release@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Release v0.3.5 (#173)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-07-03T16:31:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3f02f97935b8eb7822362ee1c3897ab18b1a8212",
          "body": "…278) (#172)\n\n* Cut Android agent per-action a11y round-trips from ~15 to 0-2 (PILOT-278)\n\nOn apps whose main thread is busy (RN animations, software-GPU CI\nemulators), every element action cost a near-uniform ~10.2s: each action\nperformed a fixed number of accessibility round-trips, each blocking o\n[…]\nwait.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01Evuy9Q4Hbj7UKkbfQx4tMu\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Cut Android agent per-action a11y round-trips from ~15 to 0-2 (PILOT-…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-03T16:05:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f3a237acc096e4a8281ca31afc1804fc8dc663cf",
          "body": "… results (#171)\n\n* Fence zombie test bodies and surface the failed attempt on flaky results\n\nRoot-caused from a DreamSpinner CI flake (run 28603029348): an auth setup\ntest hit the runner's body timeout, but Promise.race only abandons the\nbody — it kept executing, and its assertion + saveAppState ra\n[…]\nator.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01Q2E6La3fdNyQmfTaCA3sVo\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fence zombie test bodies and ship the failed attempt's trace on flaky…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-03T14:48:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "562ee3324b2cb6639f94b586e88340e3209f7481",
          "body": "Co-authored-by: tapsmith-release[bot] <tapsmith-release@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Release v0.3.4 (#169)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-07-02T14:41:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3557e93ee4986c2695d51b0f8f41e090bd5eed66",
          "body": "…gelog (#168)\n\n* Automate releases and publish notes to GitHub Releases + website changelog\n\nReplace the manual bump/tag/push flow with a one-click release:\n\n- prepare-release.yml (workflow_dispatch): computes the next version,\n  runs scripts/bump-version.sh, and opens a labelled \"Release vX.Y.Z\" PR\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01J9XXZdm3V42fjmDh7tH8MK\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Automate releases + publish notes to GitHub Releases and website chan…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-02T13:05:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b09835bdc805addc8f21254a2290d7c8bbbf381b",
          "body": "* Fix the systematic E2E CI flakes across all four components\n\nRoot-caused every E2E failure cluster from the last two weeks of CI\n(~40 iOS + 6 Android failed runs) and fixed each at the framework level:\n\n- doubleTap lands as single tap (~32 runs, both platforms): iOS now\n  dispatches two back-to-ba\n[…]\nmpts.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BeZcZRCVJnjUUFykxgPZ5t\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix the systematic E2E CI flakes across all four components (#167)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-02T13:03:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "54d8fb8eccaee0c0fc80a45447598ae9a44216d6",
          "body": "* Retry transient agent-command timeouts within the action budget\n\nOn a resource-starved CI emulator, a single findElements poll whose\non-device agent was slow to answer (Agent command timed out after 5.25s)\naborted the whole action. The SDK treated a slow-but-alive agent\nidentically to a dead one —\n[…]\nenuine assertion failure isn't reported as infra.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Retry transient agent-command timeouts within the action budget (#166)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-01T20:14:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "820d11c40008b1054e54c0abea51ca1216c85d9e",
          "body": "…) (#165)\n\n* Add retain-on-failure-and-retries trace/video mode (Playwright parity)\n\nTapsmith's trace/video `mode` set was missing Playwright's\n`retain-on-failure-and-retries` — the mode purpose-built for keeping the\ntraces of flaky tests (ones that fail then pass on retry) so the failing and\npassin\n[…]\npus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Sam Smith RB <samsmithredbadger@sams-mac.tail03406.ts.net>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add retain-on-failure-and-retries trace/video mode (Playwright parity…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-07-01T11:39:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7a67da5c40bb08706967617947c8498e4b97fb54",
          "body": "Co-authored-by: Sam Smith RB <samsmithredbadger@sams-mac.tail03406.ts.net>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Bump version to 0.3.3 (#164)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-30T20:34:44Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d2e1d91061a06ee02c5b99c22df00fa64c08344c",
          "body": "* Add --project flag to the CLI\n\nThe `tapsmith test` CLI advertised `--project` (init hints, MCP run-tests)\nbut parseArgs had no case for it, so `npx tapsmith test --project android`\nfailed with \"Unknown argument: --project\". Implement it, mirroring\nPlaywright's `--project`:\n\n- Repeatable `--project\n[…]\npus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Sam Smith RB <samsmithredbadger@sams-mac.tail03406.ts.net>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add --project flag to the CLI (#163)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-30T20:16:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ef959518343516bd8913ffdb020316c8b41b91f3",
          "body": "…162)\n\nA single run_tests call spanning multiple files counts every test in its\nsummary, but a follow-up list_results returned only the last file's results.\nTwo distinct root causes, one symptom:\n\n- Headless MCP dispatcher (headless-dispatcher.ts): the per-test result map\n  was keyed by `projectName\n[…]\null unit suite (1617) green; 4 new resultEntryKey tests.\n\n\nClaude-Session: https://claude.ai/code/session_01MpbmbeTSokU82qJjectEn4\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix list_results dropping all but the last file in multi-file runs (#…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-30T19:21:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "99ddf45a9b8908c3b6f22f6ceb19f491db3916f0",
          "body": "The MCP `tapsmith_run_tests` `test` filter was fragile and misled agents:\nexact-match only, a non-matching filter silently \"passed\" (0 passed, N\nskipped), and it was dropped entirely with >1 file. Worse, the headless\nMCP path never forwarded the filter to the child runner at all, so it ran\nthe whole\n[…]\nest(s), and a typo returns the candidate list (isError).\n\n\nClaude-Session: https://claude.ai/code/session_01DpQFu9CNbL8MU84bWF5qiX\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Make single-test filtering intuitive and fail-loud (#161)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-30T10:56:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0859b256e4b7b152d9315117fe7da0d7e2068ffb",
          "body": "Previously the reporter auto-detected `dot` when `CI` was set and `list`\notherwise. The compact `dot` output (one character per test) is hard to\ndebug from a CI log, which is often the only artifact available when a run\nfails. Default to `list` everywhere instead; `dot` remains available via an\nexpl\n[…]\nrogress output — it just no longer selects the reporter.\n\n\nClaude-Session: https://claude.ai/code/session_01R7UnHGb4xM43udut6cjEZT\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Default to the list reporter everywhere, including CI (#160)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-30T08:59:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ad42a7c4613681e46b6de111ad52d35b8615e6d7",
          "body": "* Don't gate Android element queries on global UI idle\n\nOn perpetually-animated screens (e.g. a React Native Reanimated loop plus\nindeterminate progress spinners that never finish) the accessibility-event\nstream never quiets, so the Android agent's element queries timed out\n(\"Agent command timed out\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HSqykHPJ25ppeSbTyHDwg3\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Don't gate Android element queries on global UI idle (#159)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-30T06:49:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "60d6e636336a23a2c7701308063883b5c0b10c72",
          "body": "…(#158)\n\n* Tunnel embedded-root gRPC (Firestore) that aborts the MITM handshake\n\nThe passthrough-on-cert-reject fallback (#143) only armed when the client\nrejected our generated certificate with a *decodable* TLS alert\n(`is_likely_client_cert_reject`: UnknownCA / BadCertificate). On iOS,\nFirestore's\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_012c2LCEccsBF4sJgCTfHvQH\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Tunnel embedded-root gRPC (Firestore) that aborts the MITM handshake …",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-29T20:57:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b497f9936203e67b05949822cca5811ddc581436",
          "body": "Claude-Session: https://claude.ai/code/session_01Fg6SorE6yoEEXaSySfGhpy\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Bump version to 0.3.2 (#157)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-29T10:18:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fa88698aafdb0ab64e46355ae4b6e6219374db05",
          "body": "* Fix .last()/.nth() silently tapping the wrong element on shared a11y property\n\nPositional/filtered actions resolved the correct element for reading but, when\nacting, re-derived a property-based targeting selector (resourceId →\ncontentDescription → text) and handed it to the agent — which acts on t\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019mjnHKm3AmjxiWoGJUYf22\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Address positional/filtered actions by agent-cached element id (#156)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-29T10:07:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e886caded9d74e1401c636da85f2c0b62f05379b",
          "body": "…e restore (#154)\n\n* Preserve AndroidKeyStore keys and runtime permissions across appState restore\n\nAndroid appState restore landed the app signed out whenever a `pm clear`\nran between save and restore. Two root causes:\n\n1. The per-file session preflight runs `clearAppData` (pm clear) for every\n   t\n[…]\nrd.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019Stbu2i1m3FChqu3jWWz5o\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Preserve Android auth (keystore) + runtime permissions across appStat…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-26T09:58:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8af0921cd2c1300849045d8e4728ca7ccbe02028",
          "body": "Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Bump version to 0.3.0 (#152)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-25T14:04:16Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "da3d89b047b2dfb22c2e53de9b396afa14120ccd",
          "body": "…nd (#122)\n\n* Extract shared environment scanning into env-scan module\n\nMove tryExec(), EnvScan, SimulatorInfo, and scanEnvironment() from init.ts\nto a reusable env-scan.ts module. Add parseAdbDevicesOutput() and\nlistConnectedAndroidDevices() for ADB device enumeration. This enables\ntapsmith doctor \n[…]\nored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01PJxpNMojizLoQSJaJ6c8th\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "LLM-friendly setup: non-interactive init, doctor --json, verify comma…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-25T08:59:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bc1b11fe6fa4bed64aff64ef1ae63965c31b4ab6",
          "body": "The container-level filmstrip CTA wrote `Running…` as JSX text\ncontent. JSX text doesn't process `\\u` escapes (unlike a string\nliteral), so the six characters rendered verbatim instead of an\nellipsis. Use a real `…` character, matching the per-test CTA below it.\n\n\nClaude-Session: https://claude.ai/code/session_01EQf6tyn6KGYmXeJyc7pgtV\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix literal … rendering in container \"Run\" button (#151)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-24T15:08:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "73217c2e6dca6c16b65f9dfddfa406ac976079e5",
          "body": "…(#150)\n\n* Make route.abort() surface as a request failure on all HTTP/1.1 paths (PILOT-248)\n\nroute.abort() signalled an abort by dropping the connection. Most clients\n(NSURLSession, OkHttp on x86_64) surface a closed socket as a network\nerror, but Android OkHttp on the arm64 emulator does not — the\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01B1WWCMnkcMc8geTJhqjc6q\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix route.abort() hanging instead of failing the request (PILOT-248) …",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-24T15:02:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e07fb1bbbe838a1beebd6615ced16e7fa171c244",
          "body": "* Trust the MITM CA on Android 14+ via the Conscrypt APEX store\n\nOn Android 14+ (API 34+) the runtime CA trust store moved to the Conscrypt\nAPEX (/apex/com.android.conscrypt/cacerts), independent of the legacy\n/system/etc/security/cacerts path and not made writable by `adb remount`.\nOn emulators/dev\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_0147KNup63D1Utfn8nbL5jTN\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Trust the MITM CA on Android 14+ via the Conscrypt APEX store (#149)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-24T11:48:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "06eace03d9960bac21b05318cc51d1b0359d4e7e",
          "body": null,
          "is_bot": false,
          "headline": "Show pending state for MCP-initiated test runs in UI mode (#147)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-23T23:10:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ef57bab2291192e8662cd39890f95a4359b45583",
          "body": "* Add HTTP/2 MITM pipeline: streaming capture for h2/gRPC (PILOT-245)\n\nThe MITM proxy was HTTP/1.1-only; h2-only clients (gRPC, Firestore) were\ntunnelled without interception (PILOT-231). Make h2 a first-class MITM\nprotocol so its traffic is captured and observable.\n\n- Advertise h2+http/1.1 in the M\n[…]\nx clippy dead-code warning\n\n* Keep DNS relay alive after transient UDP errors\n\n* Address DNS relay and h2 header review\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Handle Firestore HTTP/2 cert rejects with passthrough (#143)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-23T18:13:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f038cc81d0edbefe00016e7dd41766aca80a8e8e",
          "body": "…PILOT-244) (#144)\n\n* Trace element-action auto-wait so failures are attributed correctly (PILOT-244)\n\nIn UI mode, a failed test-body action whose target element never appeared\nwas not shown as the failed step. The failure and the full ~30s timeout\nwere misattributed to the last beforeAll step (e.g.\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01Mmw8EVi9cSHTvvoNeHdYw7\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Trace element-action auto-wait so failures are attributed correctly (…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-23T17:03:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "42cd0affb0bc8efc88439b2efb8de9a82b3e41b9",
          "body": "…ation (#146)\n\n* docs: correct Android appState keystore behavior + cross-device limitation\n\nThe saveAppState/restoreAppState Android docs still described the old\n`pm clear`-based restore and wrongly implied @react-native-firebase/auth\npersists via plain SharedPreferences. After the in-place-clear f\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_018cqp9EhMHtv34g4QTRapqv\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: correct Android appState keystore behavior + cross-device limit…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-23T14:10:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "08b99d761a3658a9e01b12dca90c8dc474d638a8",
          "body": "…tter (#145)\n\n* Preserve AndroidKeyStore on app-state restore; add device.platform getter\n\nAndroid `restore_app_state` used `pm clear` to reset the app's data dir\nbefore extracting the archive. `pm clear` also wipes the app's\nAndroidKeyStore keys, which on Android hold the decryption key for\ncredent\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_018cqp9EhMHtv34g4QTRapqv\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Preserve AndroidKeyStore on app-state restore; add device.platform ge…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-23T12:58:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "32a5b0a5bb6e60937641ab2095bf77241d711a44",
          "body": "* Allow getBy*/locator() scoping off modified handles\n\nMatch Playwright: `dialog.first().getByRole('button')` and other\n`getBy*`/`locator()` calls on a handle that already carries a positional\nor filtering modifier (.first/.last/.nth/.filter/.and/.or) now scope\ninto the parent instead of throwing.\n\n\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01LksuEbWFC8d5ZXdCXb1fu2\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Allow getBy*/locator() scoping off modified handles (#141)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-22T17:25:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0158d07143770e4c8b3ee12debd8fcdb8e517683",
          "body": "…ep versions (#142)\n\n* Decouple committed @tapsmith optional-dep versions from the release version\n\n`npm ci` was failing on every branch after the 0.2.0 publish:\n\n  npm error Invalid: lock file's @tapsmith/agent-android@ does not\n  satisfy @tapsmith/agent-android@0.2.0\n\nRoot cause: scripts/bump-vers\n[…]\nm ci` exits 0 and installs\nthe platform packages.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix npm ci sync failure after release: decouple committed @tapsmith d…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-19T13:12:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6223ae363f6e891e5b5b454ce46e1bf65148d790",
          "body": "Run scripts/bump-version.sh to bump all monorepo packages (TS SDK, Rust\ndaemon, platform npm packages, website footer) from 0.1.8 to 0.2.0.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Bump version to 0.2.0 (#138)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-16T21:19:31Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e11547986302dc0ce281c4912234d7a8445b3f07",
          "body": "…ILOT-221) (#136)\n\n* Fix UI-mode MCP single-session transport; add multi-client support (PILOT-221)\n\nThe UI-mode MCP server created one StreamableHTTPServerTransport for its\nwhole lifetime. In the SDK's stateful mode one transport == one session,\nso once a client initialized, a dropped SSE stream co\n[…]\nabled; this makes\n  the method itself robust too.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix UI-mode MCP single-session transport; add multi-client support (P…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-16T20:15:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "eca2cfca49610373721c04ca447886328e6329d1",
          "body": "* Tear down child resources when the dispatcher crashes (PILOT-230)\n\nA dispatcher crash (uncaught exception / unhandled rejection — the PILOT-228\nEPIPE was the observed trigger) bypassed the SIGINT/SIGTERM `emergencyCleanup`\nentirely, orphaning daemons, xcodebuild XCUITest runners, and booted\nsimula\n[…]\nrs if main() runs more than\n  once in a process).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Tear down child resources when the dispatcher crashes (PILOT-230) (#135)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-16T09:28:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c8cf6dda4308c07a73b0eae24dd52280e95ef6e6",
          "body": "…(#134)\n\n* Retry transient stale snapshots during pre-action element resolution\n\nFix recently-introduced flakiness in the Android wait-for E2E tests\n(`waitFor({ state: 'visible' })` and the downstream `attached` test).\n\nRoot cause: PILOT-226 (#124) switched strict pre-action resolution for\nunmodifie\n[…]\nng count (verified it returns 0 without the fix).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Retry transient stale snapshots during pre-action element resolution …",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-15T21:51:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "abcf3476ba80f186aeb7fd450ba73591f21343ca",
          "body": "…#133)\n\nWhen watching a live run in UI mode and selecting the in-progress\n(currently-executing) action, the Source tab showed \"No source files in\ntrace\" instead of the test source with the current line highlighted.\nOnce the action completed, the source appeared as expected.\n\nThe source file is alrea\n[…]\nmpleted actions, showing the file with the current line\nhighlighted. Client-only change; no worker/server/proto/streaming\nchanges.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix empty Source tab for in-progress actions in UI mode (PILOT-233) (…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-15T10:31:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "79c8db29175a3fbe0efc0acabde48a3598026f0f",
          "body": null,
          "is_bot": false,
          "headline": "Fix trace viewer not deploying to production on tag push (#132)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-13T21:49:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9f47c8bdc8b10bfeaafc6fea934f35814d58e098",
          "body": "…run (PILOT-228) (#131)",
          "is_bot": false,
          "headline": "Stop dispatcher crashing with unhandled EPIPE when a worker dies mid-…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-12T18:02:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "044c99ac9941a8e8bf3ec3ee41833f297f952986",
          "body": "…) (#130)\n\n* Make video on-first-retry mode production-ready + switch CI to it (PILOT-240)\n\nThe on-first-retry video mode (no recorder at all on attempt 1, record\nonly the first retry) already existed from PILOT-114 and the runner\ngating works — verified on an iOS simulator: a failing test with\nretr\n[…]\nfirst-retry +\ntrace on-all-retries + retries: 0 prints exactly one line each.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Video on-first-retry: startup warning, docs, and CI switch (PILOT-240…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-12T15:29:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4214e1b6d74712ee9d19efdaa1c472b0381696c9",
          "body": "* Live progress feedback during long device actions (PILOT-232)\n\nLong device actions (save/restore app state, clearAppData, restartApp,\nlaunchApp, session preflight between files) ran with no live output, so\nboth headless CLI and UI mode were indistinguishable from a hang for\n5-60s+. Trace recording\n[…]\nn blips.\n\nAlso extract a nested template literal in the failure line (S4624).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Live progress feedback during long device actions (PILOT-232) (#128)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-12T12:43:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f0630e2cd521130f9de15097f791b129794b76a9",
          "body": "…(PILOT-235) (#129)\n\n* Stop no longer leaks video recording + network capture on the daemon (PILOT-235)\n\nSince PILOT-222, stopping a run cancelled not just the in-flight test\naction but also the trace-finalization cleanup RPCs, orphaning the video\nrecorder (and capture session) on the daemon. Every \n[…]\n>\n\n* Document why the recording-slot lock is held across discard/start awaits\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Stop no longer leaks video recording + network capture on the daemon …",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-12T12:42:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7c4f85be7e9aae912e9581a3fafff8cdd2884e30",
          "body": "…r wedged workers (PILOT-222) (#127)\n\n* Make stop actually stop tests immediately, with SIGKILL escalation for wedged workers (PILOT-222)\n\nStop was purely cooperative: the runner only checked the abort signal\nbetween tests, nothing cancelled in-flight gRPC calls or polling loops,\nand a wedged worker\n[…]\n rethrowing, so a later idle-state abort\n  IPC can't poke a stale controller.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Make stop actually stop tests immediately, with SIGKILL escalation fo…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-11T21:40:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9e26d69c0cd35cbb637faba9a8910c382bcd1827",
          "body": "…g them (PILOT-231) (#126)\n\n* Tunnel HTTP/2-only and pinned-host TLS connections instead of dropping them (PILOT-231)\n\nThe MITM proxy parsed all decrypted traffic as HTTP/1.1 and never\nadvertised ALPN, so HTTP/2-only clients (gRPC-Core/BoringSSL — Firestore,\ngRPC APIs) reset right after the TLS hand\n[…]\nk read guard before awaiting, instead of\n  holding the guard across the call.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Tunnel HTTP/2-only and pinned-host TLS connections instead of droppin…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-11T15:27:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5307c69cd5151f588567897c2b182bbcd1ce01dd",
          "body": "…-220) (#125)\n\n* Capture iOS simulator keychain in app state save/restore/clear (PILOT-220)\n\nOn iOS simulators the keychain lives at the device level, outside the\napp data container, so saveAppState archives never included\nkeychain-backed state (native Firebase Auth sessions, expo-secure-store\nitems\n[…]\ns work.\n\nKeychain e2e re-verified (round-trip + clearAppData wipe) on iOS 26.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Capture iOS simulator keychain in app state save/restore/clear (PILOT…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-11T14:17:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "23940970b717bd3887355bda924ab0550230b9ad",
          "body": "…6) (#124)\n\n* Add Playwright-style strict mode to locator actions and assertions\n\nA locator that resolves to more than one element now throws\nStrictModeViolationError (listing every match with an unambiguous\nselector suggestion) instead of silently acting on the first match in\ndocument order. Applie\n[…]\n (nth out-of-range) instead of returning an empty result.\n\nPart of PILOT-226.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Strict mode for locators + runtime-true selector validation (PILOT-22…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-10T22:29:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7c58640b3f64eac7ae3dc4d9000bcc40d1992663",
          "body": "* Pin website deploy to production branch on Cloudflare Pages\n\nThe deploy-website workflow triggers on v* tags, so actions/checkout\nlands in detached HEAD. With no --branch flag, wrangler infers the\nbranch alias `head`, which Cloudflare Pages treats as a preview\ndeployment. As a result every \"succes\n[…]\nry real\nversion/resolved/integrity entries again.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Pin website deploy to production branch on Cloudflare Pages (#123)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-10T13:52:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b9ce3c53dda51a6a10bc389fc0298b39078ad47e",
          "body": "…(#121)\n\n* Fix iOS simulator agent npm packages shipping without the app bundle\n\nEvery published @tapsmith/agent-ios-simulator-{arm64,x64} version\n(0.1.3-0.1.7) contained only the .xctestrun files: npm-packlist does not\nrecurse into wildcard directory globs, so the `sdk-*/` files entry\nmatched nothi\n[…]\nes drops optional-peer entries and breaks npm ci.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix iOS simulator agent npm packages shipping without the app bundle …",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-10T10:36:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "00226d09feaf2146ee112a7638ba024baf931eed",
          "body": "…#110)\n\n* Fix explicit test files only running against first matching project\n\nWhen running `tapsmith test path/to/file.test.ts` with a multi-project\nconfig, `findProjectForFile` returned only the first matching project\nname. Files matching multiple projects (e.g. the same test running on\nboth Andro\n[…]\nr match nothing instead of being matched as\nraw absolute paths.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix explicit test files only running against first matching project (…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-10T08:55:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4492dd3f033782d24d0901caffdcb59a3f807817",
          "body": "Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Bump version to 0.1.7 (#120)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-10T08:52:09Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0644c9893bda1ec09678f7fce9144a19ea26b11c",
          "body": "* Auto-uninstall and retry on Android agent signature mismatch\n\nWhen adb install fails with INSTALL_FAILED_UPDATE_INCOMPATIBLE (the\nAPK was signed with a different key than the installed version), parse\nthe package name from the error message, uninstall the old package,\nand retry the install.\n\nCo-Au\n[…]\n fail a pick\n  that the original hit node would have satisfied.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Auto-retry Android agent install on signature mismatch (#119)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-10T07:54:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c61bce1b44662994738cb0b8a11ea869a65b7db7",
          "body": "* Fix CJS/ESM dual-instance crash in test runner\n\nWhen a project lacks \"type\": \"module\" in package.json, tsx loads test\nfiles as CJS. The CJS require() of tapsmith creates a separate module\ninstance from the runner's ESM import, giving it its own empty\ncontextStack — so describe()/test() calls crash\n[…]\necause the CJS instance's collector is never set.\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix CJS/ESM dual-instance crash in test runner (#118)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-09T13:36:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f18c681782c2cf27a4e6e39d3375bffa0fa9166a",
          "body": "Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix iOS agent startup race with concurrent app install (#117)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-09T10:48:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3952982fd0eaa26e15eadccb90877032c3677adb",
          "body": "Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix: strip DSTROOTPath from auto-built iOS simulator xctestrun (#116)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-09T08:51:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "03a71bdde6d036537e7ca5ebe1f045781c265a67",
          "body": "* ci: use macos-26 for iOS simulator agent build\n\nEnsures the prebuilt @tapsmith/agent-ios-simulator-* packages are\nbuilt against the iOS 26 SDK, matching users on Xcode 26.\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n* feat: add extractSdkVersion() for xctestrun SDK detec\n[…]\nureSimulatorAgent handle iOS xctestrun resolution in CI\"\n\nThis reverts commit c25ef8aa460a03b64ab9196424a743ce6a882552.\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Auto-build iOS simulator agent on SDK version mismatch (#115)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-09T07:05:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5b6bd2bf2a04f48733902eb36918f099b7edac0e",
          "body": "…#114)\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Extract Android agent into separate @tapsmith/agent-android package (…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-08T16:43:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "da8ad015f7c68062957a1b4cf6fc815a6f4b609e",
          "body": "Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Skip optional deps in CI workflows to prevent lockfile mismatch (#113)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-08T15:41:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fc331cb1c0cf9fbf811b2f3457bbe1e7381d8bd3",
          "body": "The optional @tapsmith/core-* and agent-ios-simulator-* packages are\npublished earlier in the same pipeline, so the lockfile won't have\nmatching versions yet. npm ci rejects the mismatch; npm install\nresolves them from the registry.\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Use npm install instead of npm ci for tapsmith publish step (#112)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-08T15:18:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b6538d6c6c2bc25f093ee15f718e9f8ffd5fc0d5",
          "body": "The arch-specific destination (platform=iOS Simulator,arch=arm64) no\nlonger resolves to a device on current Xcode. Use the generic\ndestination with explicit ARCHS build setting instead, which works\non both macos-15 and macos-26 runners.\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix iOS simulator agent build in release workflow (#111)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-08T15:02:51Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5a7d12d7552d536f2d245bb473cce40414a5b125",
          "body": "* fix: pass --platform to daemon in dispatcher (skip ADB on iOS)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\n\n* perf: skip clearAppData + restartApp on initial startup launch\n\nOn first launch after fresh install, there's no app state to clear.\nSkip the expensive clearAppData → restart\n[…]\n file-level reset for the first file\nof an appState project.\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf: startup optimisations (CI + local) (#108)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-08T14:19:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ad837cc974fbfb3253acc4b1c43a15bd98b0190a",
          "body": "* Fix chronic iOS auth.setup attempt-1 deep-link flake\n\nThe very first deep link on a fresh simulator (auth.setup's\n`tapsmithtest:///login`) fails on attempt 1 on virtually every iOS e2e\nrun, then passes on retry. It is the only cold, untrusted launch: first\nRN process start on a fresh sim plus the \n[…]\n.\n\nVerified: cargo fmt + clippy -D warnings pass.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix chronic iOS auth.setup attempt-1 deep-link flake (#105)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-05T12:52:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5f2ad5d81c1a65d6dbfd56b9646fd67ab419c313",
          "body": "* Add batched captureTraceState command to reduce iOS trace overhead\n\nEvery traced action on iOS triggered 3 sequential agent commands\n(screenshot, hierarchy, findElement), each taking a separate\napp.snapshot() IPC (~50ms each). The agent processes commands serially\non the main RunLoop, so parallel \n[…]\n iOS batched trace fallback regressions\n\n* Avoid redundant iOS hierarchy snapshot retry\n\n* Map trace state command name\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add batched captureTraceState command to reduce iOS trace overhead (#88)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-04T14:14:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a7dc1d6c572342d387cc60aec4565b7f47da1ca7",
          "body": "… (#89)\n\n* Speed up iOS e2e: skip blind settle wait + add timing instrumentation\n\nProfiling one iOS shard (8 files, iPhone 16) with new opt-in timing shows\nper-command device latency dominates wall-clock, not agent boot:\n\n  agent boot:     ~16s (once/shard)\n  app reset:      ~5s\n  command total:  ~1\n[…]\neGetCurrent, so NTP/clock\n  adjustments can't skew the elapsed-time checks.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Speed up iOS e2e: skip blind settle wait + add timing instrumentation…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-04T13:21:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d5f57861c041f8d363015054b6e89f85ad9e6e24",
          "body": "The interactive device mirror in UI mode gained an Android-only live H.264\nvideo stream (decoded in-browser via WebCodecs) alongside the screenshot\nstream. The screenshot stream is more reliable, so drop the video path\nentirely and always mirror via screenshots.\n\nRemoved across all tiers:\n- proto: S\n[…]\ndroid)\" note from docs/ui-mode.md\n\nVideo *recording* (PILOT-114: the `video` config / MP4 export) is unrelated\nand left untouched.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Remove live video stream from the device mirror (screenshot-only) (#104)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-04T12:18:07Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e9ce4ef89e2987eefd446b87c769daec62be978d",
          "body": "* Fix UI mode: hard-refresh (Cmd+Shift+R) no longer starts a test run\n\nThe keyboard-shortcut handler matched bare letter keys (r -> run-all,\nf -> run-failed, w -> toggle-watch) without checking modifier keys. A\nbrowser hard-refresh dispatches keydown to the page before navigating\naway, so Cmd+Shift+\n[…]\ndd\n  Shift+Escape and contenteditable test cases.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix UI mode: hard-refresh no longer starts a test run (#103)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-04T11:46:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "80b837225194249126a190693046c2ac451105ad",
          "body": "* Use photographic device bezels in UI mode and the trace viewer\n\nReplace the hand-drawn CSS device bezels with real photographic frames\n(iPhone + Pixel) extracted once from the bezel.fit API, applied per device\ntype. The CSS bezels remain as a fallback.\n\n- scripts/fetch-bezels.mjs: one-time extract\n[…]\nm/form factor changes\n  so a transient failure (or switching devices) doesn't permanently fall back\n  to the CSS bezel.\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Use photographic device bezels in UI mode and the trace viewer (#102)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-04T10:45:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "000babc32b19b87124b1d4f173765d415539ac80",
          "body": null,
          "is_bot": false,
          "headline": "Guard iOS inputText typing (#99)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-03T22:44:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "93d3c1da3ec983cf9a876fa99653e019042ff882",
          "body": "* Fix iOS deep-link open prompt flake\n\n* Address iOS deep-link review feedback\n\n* Add iOS deep-link CI diagnostics\n\n* Address iOS deep-link review comments\n\n* Optimize iOS openurl prompt polling\n\n* Address iOS deep-link review comments\n\n* Skip soft reset during app startup\n\n* Use global worker ids for daemon logs\n\n* Harden iOS openurl prompt handling",
          "is_bot": false,
          "headline": "Fix iOS deep-link Open prompt flake (#97)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-03T16:15:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5208e7297da2f1df94209f4a4243f7adba94ef43",
          "body": "* feat(proto): add StreamDaemonLogs RPC for daemon log capture\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n* feat(core): add daemon log broadcast bus + tracing layer\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n* feat(core): wire daemon log layer \n[…]\non every daemon log line during normal test runs.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Stream daemon logs into trace files (trace.daemonLogs) (#101)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-03T14:40:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d082657ba9e20d1d21bee4891d6ced717b18ed19",
          "body": "* docs(ui-mode): document the interactive device mirror\n\nPR #98 made the UI-mode device mirror interactive but ui-mode.md still described\nit as view-only. Document tap/swipe/long-press/text input, the lock toggle\n(auto-locks during runs, user-overridable), and live H.264 video for the single\nAndroid\n[…]\ni-mode): note Android video falls back to screenshots\n\nPer Gemini review: the live H.264 stream falls back to screenshot streaming when\nWebCodecs is unsupported or the decoder errors (useVideoMirror).",
          "is_bot": false,
          "headline": "docs(ui-mode): document the interactive device mirror (#100)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-03T10:39:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8b280d907e3364a7eed8ba85fef688276e9bc921",
          "body": "* proto: add coordinate gesture and InputText RPCs\n\n* daemon: add coordinate gesture AgentCommand variants\n\nAdd TapCoordinates, LongPressCoordinates, DragCoordinates, and InputText\nvariants to AgentCommand with serialization match arms and four new tests.\nAdd unimplemented stubs to grpc_server.rs to\n[…]\n) before boundingBox(): a gone item is the strongest\nproof the drag scrolled. The feature works — this was a test-only assumption.\n\n---------\n\nCo-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Interactive device mirror in UI mode (tap/swipe/long-press/text) (#98)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-06-03T08:47:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a59cff5706899a6b56f899a7e7c57ff80274c8c6",
          "body": "* Add design spec: UI mode source tab reads actual source files\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n* Add implementation plan: UI mode source tab reads actual source files\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n* Tighten plan: exact \n[…]\nedence (trace snapshot wins), no behavior change.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "UI mode Source tab reads actual source files (Playwright-style) (#94)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-31T22:30:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ffc9d25c91abd8100cec2040237816ecdce0521d",
          "body": "* Resolve test-scoped fixtures in beforeAll/afterAll hooks\n\nTest-scoped custom fixtures (e.g. page-object screens) were unavailable\nin `beforeAll`/`afterAll` hooks: the runner only injected worker-scoped\nfixtures and builtins, so a hook destructuring a test-scoped fixture\nreceived `undefined` (and o\n[…]\nit) instead of querying via the builtin `device`.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Resolve test-scoped fixtures in beforeAll/afterAll hooks (#95)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-31T21:51:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e7d45c91388386d089f260af45498af850a1fe7a",
          "body": "* Type-check the web apps and lint the trace viewer in CI\n\n`tsc --noEmit` only covered the Node SDK (include: src/**/*.ts, no JSX/DOM\nlib), so the entire UI-mode + trace-viewer Preact component layer was never\ntype-checked; the lint script also excluded src/trace-viewer/ entirely.\n\n- Add tsconfig.ap\n[…]\nrigImpl/opts in the filterHealthySimulators test.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Type-check the web apps and lint the trace viewer in CI (#93)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-29T22:47:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "08cfd32d5259aa5ce1296459a2baba3f44e58aa1",
          "body": "…ce viewer (#92)\n\n* Add Tapsmith branding and website-matched dark theme to UI mode & trace viewer\n\n- Branding: coral logo mark + \"Tapsmith\" wordmark lockup in the UI mode and\n  trace viewer rails (top-aligned, theme-aware wordmark) and the coral favicon.\n  Brand PNGs are cropped from the website lo\n[…]\ntact while guarding against pathological inlines.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add Tapsmith branding and website-matched dark theme to UI mode & tra…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-29T22:27:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "21eee8a2207dffa3cc0105b7441fa7a62edad8fb",
          "body": null,
          "is_bot": false,
          "headline": "Make tapsmith SDK ESM-first (#91)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-29T18:32:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7d1e063b8811a96509bd056478b0c03872519078",
          "body": "…#90)\n\n* Fix list reporter duplicate in-progress lines in single-worker mode\n\nIn single-worker mode tests run in-process, so their stdout/stderr (e.g.\nconsole.log) interleaves with the reporter's output between onTestStart\n(which prints the dimmed in-progress row) and onTestEnd (which clears it).\n\n_\n[…]\nbytes emitted.\n\nAddresses review feedback on #90.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix list reporter duplicate in-progress lines in single-worker mode (…",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-29T16:04:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7ad2a5a3dc5eb4256b03cef21db7ccb2ae36e9e7",
          "body": "* Add PersistentStream type and send_with_persistent_cache function\n\nIntroduces the persistent TCP connection infrastructure without wiring\nit into the gRPC server yet. The cached stream is lazily connected,\nautomatically reconnected on broken pipe, and invalidated on timeout.\n\nCo-Authored-By: Claud\n[…]\nthe next command reconnects to the correct agent.\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Persistent TCP connection to on-device agent (#86)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-28T11:04:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4f821f4f8433cba744b03f84a43845787b8a2c57",
          "body": "* Add .worktrees/ to gitignore\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n* Refactor E2E tests: screen fixtures and deeplink navigation\n\nIntroduce e2e/fixtures.ts that extends test with all 12 screen objects\nas test fixtures via test.extend(), following the Playwright pat\n[…]\nich can fail on frozen/sealed/proxied\n  functions\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Refactor E2E tests: screen fixtures and deeplink navigation (#84)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-27T20:52:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b5c52dbcc821f7e68058009df2bacd85d2f26f2f",
          "body": "* Add .worktrees/ to gitignore\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n* Exclude caches from app state archives for faster save/restore\n\niOS simulator containers accumulate significant cached data\n(Library/Caches, Library/WebKit, Library/SplashBoard, tmp) that\ninflates\n[…]\nr_cmd closure instead of requiring trailing space\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Exclude caches from app state archives for faster save/restore (#85)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-27T08:06:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "97748903a081d9409228b031187b24d35f24fe72",
          "body": "* Implement reset app deep link for E2E\n\n* Address reset app PR feedback\n\n* Address reset route review comments\n\n* Stabilize reset helper and network mocking tests\n\n* Avoid cached route fetch responses in E2E\n\n* Use soft reset for iOS network mocking tests\n\n* Stabilize Android network capture reset \n[…]\ncross soft resets\n\n* Avoid holding proxy lock while draining capture\n\n* Guard network trace teardown on device\n\n* Bail early on terminal adb reverse errors\n\n* Clarify device narrowing in trace cleanup",
          "is_bot": false,
          "headline": "Implement reset app deep link in E2E (#83)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-26T22:07:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d6d436a36320823f2916d6bae4ae74f187c72061",
          "body": "* Fix flaky tests\n\n* Address flaky test review comments",
          "is_bot": false,
          "headline": "Fix flaky tests (#82)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-24T06:21:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ccd3a10f30095b0ddfadce9e2cdd81723540f0c9",
          "body": "* Show file names and in-progress tests in list reporter\n\nAdd filePath to TestResult and serialize it over IPC so the list\nreporter can show the test file name inline with each result in\nparallel mode, matching Playwright's output format:\n\n  ✓ [1] › login.test.ts › authenticates user (2.1s)\n\nAdd onT\n[…]\nge cases\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n* Improve list reporter progress output\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Match Playwright list reporter output format (#81)",
          "author_name": "Sam Smith",
          "author_login": "samsmithyeah",
          "committed_at": "2026-05-23T21:40:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 16,
      "commits_last_year": 227,
      "latest_release_at": "2026-07-18T12:36:24Z",
      "latest_release_tag": "v0.4.0",
      "releases_from_tags": false,
      "days_since_last_push": 4,
      "active_weeks_last_year": 18,
      "days_since_latest_release": 5,
      "mean_days_between_releases": 1.8
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "website",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "scraping",
            "web"
          ],
          "ecosystem": "npm",
          "matches_repo": false,
          "registry_url": "https://www.npmjs.com/package/website",
          "is_deprecated": false,
          "latest_version": "0.1.1",
          "repository_url": "https://github.com/akoenig/node-website",
          "versions_count": 2,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 1191,
          "first_published_at": "2013-04-29T19:45:26.593000Z",
          "latest_published_at": "2013-05-14T20:47:23.347000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 4817
        },
        {
          "name": "tapsmith",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [
            "mobile",
            "testing",
            "android",
            "ios",
            "automation",
            "ui-testing"
          ],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/tapsmith",
          "is_deprecated": false,
          "latest_version": "0.4.0",
          "repository_url": "https://github.com/samsmithyeah/tapsmith",
          "versions_count": 17,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 1569,
          "first_published_at": "2026-04-22T20:46:30.972000Z",
          "latest_published_at": "2026-07-18T12:36:12.063000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        },
        {
          "name": "@tapsmith/agent-android",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@tapsmith/agent-android",
          "is_deprecated": false,
          "latest_version": "0.4.0",
          "repository_url": "https://github.com/samsmithyeah/tapsmith",
          "versions_count": 14,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 3128,
          "first_published_at": "2026-06-09T07:08:52.581000Z",
          "latest_published_at": "2026-07-18T12:33:12.062000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        },
        {
          "name": "@tapsmith/core-linux-x64",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@tapsmith/core-linux-x64",
          "is_deprecated": false,
          "latest_version": "0.4.0",
          "repository_url": "https://github.com/samsmithyeah/tapsmith",
          "versions_count": 16,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 2617,
          "first_published_at": "2026-04-24T16:14:36.841000Z",
          "latest_published_at": "2026-07-18T12:35:04.266000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        },
        {
          "name": "@tapsmith/core-darwin-x64",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@tapsmith/core-darwin-x64",
          "is_deprecated": false,
          "latest_version": "0.4.0",
          "repository_url": "https://github.com/samsmithyeah/tapsmith",
          "versions_count": 16,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 1569,
          "first_published_at": "2026-04-24T16:14:22.983000Z",
          "latest_published_at": "2026-07-18T12:34:48.147000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        },
        {
          "name": "@tapsmith/core-linux-arm64",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@tapsmith/core-linux-arm64",
          "is_deprecated": false,
          "latest_version": "0.4.0",
          "repository_url": "https://github.com/samsmithyeah/tapsmith",
          "versions_count": 16,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 1475,
          "first_published_at": "2026-04-24T16:14:49.880000Z",
          "latest_published_at": "2026-07-18T12:35:20.859000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        },
        {
          "name": "@tapsmith/core-darwin-arm64",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@tapsmith/core-darwin-arm64",
          "is_deprecated": false,
          "latest_version": "0.4.0",
          "repository_url": "https://github.com/samsmithyeah/tapsmith",
          "versions_count": 16,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 2231,
          "first_published_at": "2026-04-24T16:14:11.055000Z",
          "latest_published_at": "2026-07-18T12:34:32.568000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        },
        {
          "name": "@tapsmith/agent-ios-simulator-x64",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@tapsmith/agent-ios-simulator-x64",
          "is_deprecated": false,
          "latest_version": "0.4.0",
          "repository_url": "https://github.com/samsmithyeah/tapsmith",
          "versions_count": 15,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 1274,
          "first_published_at": "2026-06-08T15:15:31.107000Z",
          "latest_published_at": "2026-07-18T12:33:25.993000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 8,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 8
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": true,
      "bootstrap_files": [],
      "api_schema_files": [
        "packages/tapsmith-core/vendor/mitmproxy_ipc.proto",
        "proto/tapsmith.proto"
      ],
      "has_devcontainer": false,
      "typecheck_configs": [
        "packages/tapsmith/tsconfig.json",
        "test-app/tsconfig.json",
        "website/tsconfig.json"
      ],
      "toolchain_manifests": [
        "agent/app/build.gradle.kts",
        "agent/build.gradle.kts",
        "packages/tapsmith-core/Cargo.toml"
      ],
      "largest_source_bytes": 332289,
      "source_files_sampled": 388,
      "oversized_source_files": 18,
      "agent_instruction_files": [
        "CLAUDE.md",
        "docs/agents.md"
      ],
      "agent_instruction_max_bytes": 8640
    },
    "dependencies": {
      "manifests": [
        "agent/build.gradle.kts",
        "e2e/package.json",
        "test-app/package.json",
        "website/package.json"
      ],
      "advisories": {
        "error": null,
        "scope": "published_package",
        "source": "osv",
        "findings": [
          {
            "name": "@hono/node-server",
            "direct": false,
            "version": "1.19.14",
            "severity": "moderate",
            "ecosystem": "npm",
            "cvss_score": 5.9,
            "advisory_ids": [
              "GHSA-frvp-7c67-39w9"
            ],
            "fixed_version": "2.0.5",
            "advisory_count": 1,
            "oldest_advisory_days": 2
          }
        ],
        "collected": true,
        "malicious": [],
        "truncated": false,
        "by_severity": {
          "moderate": 1
        },
        "advisory_count": 1,
        "affected_count": 1,
        "assessed_count": 203,
        "malicious_count": 0,
        "assessed_package": "npm:tapsmith@0.4.0",
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "maven",
        "npm"
      ],
      "dependencies": [
        {
          "name": "tapsmith",
          "manifest": "e2e/package.json",
          "ecosystem": "npm",
          "version_constraint": "file:../packages/tapsmith"
        },
        {
          "name": "@expo/vector-icons",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "^15.0.2"
        },
        {
          "name": "@react-native-async-storage/async-storage",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.2.0"
        },
        {
          "name": "expo",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~55.0.6"
        },
        {
          "name": "expo-camera",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~55.0.9"
        },
        {
          "name": "expo-clipboard",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~55.0.8"
        },
        {
          "name": "expo-constants",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~55.0.7"
        },
        {
          "name": "expo-linking",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~55.0.7"
        },
        {
          "name": "expo-location",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~55.1.2"
        },
        {
          "name": "expo-router",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~55.0.5"
        },
        {
          "name": "expo-secure-store",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~55.0.14"
        },
        {
          "name": "expo-status-bar",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~55.0.4"
        },
        {
          "name": "react",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "19.2.0"
        },
        {
          "name": "react-native",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "0.83.2"
        },
        {
          "name": "react-native-safe-area-context",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~5.6.2"
        },
        {
          "name": "react-native-screens",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "~4.23.0"
        },
        {
          "name": "react-native-webview",
          "manifest": "test-app/package.json",
          "ecosystem": "npm",
          "version_constraint": "^13.12.5"
        },
        {
          "name": "@astrojs/starlight",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.39.2"
        },
        {
          "name": "@tailwindcss/vite",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.3.0"
        },
        {
          "name": "astro",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^6.3.1"
        },
        {
          "name": "sharp",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.34.5"
        },
        {
          "name": "starlight-image-zoom",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.14.2"
        },
        {
          "name": "starlight-links-validator",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.24.0"
        },
        {
          "name": "tailwindcss",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.3.0"
        },
        {
          "name": "tonic",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.12"
        },
        {
          "name": "prost",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.13"
        },
        {
          "name": "tokio",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1"
        },
        {
          "name": "tokio-stream",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.1"
        },
        {
          "name": "hyper",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1"
        },
        {
          "name": "hyper-util",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.1"
        },
        {
          "name": "http-body-util",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.1"
        },
        {
          "name": "h2",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.4"
        },
        {
          "name": "http",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1"
        },
        {
          "name": "bytes",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1"
        },
        {
          "name": "serde",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1"
        },
        {
          "name": "serde_json",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1"
        },
        {
          "name": "anyhow",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1"
        },
        {
          "name": "thiserror",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "2"
        },
        {
          "name": "tracing",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.1"
        },
        {
          "name": "tracing-subscriber",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.3"
        },
        {
          "name": "uuid",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1"
        },
        {
          "name": "base64",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.22"
        },
        {
          "name": "rcgen",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.13"
        },
        {
          "name": "x509-parser",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.16"
        },
        {
          "name": "md-5",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.10"
        },
        {
          "name": "time",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.3"
        },
        {
          "name": "tokio-rustls",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.26"
        },
        {
          "name": "rustls",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.23"
        },
        {
          "name": "rustls-pemfile",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "2"
        },
        {
          "name": "webpki-roots",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.26"
        },
        {
          "name": "dirs",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "6.0.0"
        },
        {
          "name": "async-trait",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.1"
        },
        {
          "name": "regex",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1"
        },
        {
          "name": "url",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "2"
        },
        {
          "name": "crc32fast",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1.4"
        },
        {
          "name": "plist",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1.7"
        },
        {
          "name": "tempfile",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "3"
        },
        {
          "name": "libc",
          "manifest": "packages/tapsmith-core/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.2"
        },
        {
          "name": "@grpc/grpc-js",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.12.0"
        },
        {
          "name": "@grpc/proto-loader",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.7.13"
        },
        {
          "name": "@modelcontextprotocol/sdk",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.29.0"
        },
        {
          "name": "bplist-creator",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.1.1"
        },
        {
          "name": "bplist-parser",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.3.2"
        },
        {
          "name": "chokidar",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.0.3"
        },
        {
          "name": "enquirer",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.4.1"
        },
        {
          "name": "fflate",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.8.2"
        },
        {
          "name": "figlet",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.11.0"
        },
        {
          "name": "glob",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^11.0.0"
        },
        {
          "name": "minimatch",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^10.2.4"
        },
        {
          "name": "open",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^10.2.0"
        },
        {
          "name": "proper-lockfile",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.1.2"
        },
        {
          "name": "tsx",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.21.0"
        },
        {
          "name": "ws",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^8.20.0"
        },
        {
          "name": "zod",
          "manifest": "packages/tapsmith/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.3.6"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 6,
        "merged_prs": 178,
        "open_issues": 2,
        "closed_ratio": 0,
        "closed_issues": 0,
        "closed_unmerged_prs": 8
      },
      "bus_factor": 1,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "samsmithyeah",
          "commits": 224,
          "avatar_url": "https://avatars.githubusercontent.com/u/22592849?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "deploy-trace-viewer.yml",
        "deploy-website.yml",
        "e2e-android.yml",
        "e2e-ios.yml",
        "ios.yml",
        "prepare-release.yml",
        "preview-trace-viewer.yml",
        "preview-website.yml",
        "release.yml",
        "tag-release.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [
        "eslint.config.mjs"
      ],
      "has_editorconfig": false,
      "has_linter_config": true,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "Cargo.lock",
        "package-lock.json"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 9,
            "reason": "binaries present in source code",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 3,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/27 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 3,
            "reason": "dependency not pinned by hash detected -- score normalized to 3",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 0,
            "reason": "92 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "d7293e51ae96a8646f1b3e9d1918f106a39391ab",
        "ran_at": "2026-07-23T20:14:11Z",
        "aggregate_score": 4,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-18T12:37:12Z",
      "oldest_open_prs": [
        {
          "number": 87,
          "created_at": "2026-05-28T11:04:38Z",
          "last_comment_at": "2026-05-28T21:49:07Z",
          "last_comment_author": "samsmithyeah"
        },
        {
          "number": 109,
          "created_at": "2026-06-07T17:20:15Z",
          "last_comment_at": "2026-06-07T17:20:51Z",
          "last_comment_author": "github-actions"
        },
        {
          "number": 139,
          "created_at": "2026-06-16T21:32:50Z",
          "last_comment_at": "2026-06-25T09:11:31Z",
          "last_comment_author": "samsmithyeah"
        },
        {
          "number": 148,
          "created_at": "2026-06-24T09:27:18Z",
          "last_comment_at": "2026-06-24T14:26:06Z",
          "last_comment_author": "samsmithyeah"
        },
        {
          "number": 193,
          "created_at": "2026-07-18T17:30:06Z",
          "last_comment_at": "2026-07-18T17:30:33Z",
          "last_comment_author": "coderabbitai"
        },
        {
          "number": 194,
          "created_at": "2026-07-18T21:22:48Z",
          "last_comment_at": "2026-07-18T21:23:28Z",
          "last_comment_author": "github-actions"
        }
      ],
      "last_merged_pr_at": "2026-07-18T12:30:32Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 50,
          "created_at": "2026-05-06T12:38:52Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 187,
          "created_at": "2026-07-11T18:59:10Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/samsmithyeah/tapsmith",
    "host": "github.com",
    "name": "tapsmith",
    "owner": "samsmithyeah"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 61,
      "inputs": {
        "security": 50,
        "vitality": 86,
        "community": 40,
        "governance": 44,
        "engineering": 80
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "excellent",
        "name": "Vitality",
        "value": 86,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 76,
            "inputs": {
              "commits_last_year": 227,
              "human_commit_share": 0.97,
              "days_since_last_push": 4,
              "active_weeks_last_year": 18
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 4 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "18/52 weeks with commits",
                "points": 12.5,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 18
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "227 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 227
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "releases_count": 16,
              "latest_release_tag": "v0.4.0",
              "releases_from_tags": false,
              "days_since_latest_release": 5,
              "mean_days_between_releases": 1.8
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "16 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 16
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~1.8 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 1.8
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 40,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 14,
            "inputs": {
              "forks": 0,
              "stars": 8,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "8 stars",
                "points": 13.7,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 8
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (Apache-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "Apache-2.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 69,
            "inputs": {
              "packages": [
                "tapsmith",
                "@tapsmith/agent-android",
                "@tapsmith/core-linux-x64",
                "@tapsmith/core-darwin-x64",
                "@tapsmith/core-linux-arm64",
                "@tapsmith/core-darwin-arm64",
                "@tapsmith/agent-ios-simulator-x64"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 13863
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "13,863 downloads/month across npm",
                "points": 55.2,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 13863,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 44,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 13,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "at_risk",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 37,
            "inputs": {
              "merged_prs": 178,
              "open_issues": 2,
              "closed_issues": 0,
              "issue_closed_ratio": 0,
              "closed_unmerged_prs": 8
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "0% of issues closed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 0
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "178/186 decided PRs merged",
                "points": 36.6,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 178,
                      "decided": 186
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/27 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 43,
            "inputs": {
              "followers": 3,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "samsmithyeah",
              "public_repos": 12,
              "account_age_days": 3580
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "3 followers of samsmithyeah",
                "points": 4.3,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 3,
                      "login": "samsmithyeah"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "12 public repos, account ~9 yr old",
                "points": 20.1,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 12
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 9
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "tapsmith",
                "@tapsmith/agent-android",
                "@tapsmith/core-linux-x64",
                "@tapsmith/core-darwin-x64",
                "@tapsmith/core-linux-arm64",
                "@tapsmith/core-darwin-arm64",
                "@tapsmith/agent-ios-simulator-x64"
              ],
              "ecosystems": "npm",
              "any_deprecated": false,
              "min_days_since_publish": 5
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "7 package(s) on npm",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 7,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 5 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "17 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 17
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "good",
        "name": "Engineering Quality",
        "value": 80,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 84,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "11 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 11
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": "eslint.config.mjs",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "eslint.config.mjs"
                    }
                  }
                ],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 50,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 40,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 4
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "binaries present in source code",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/27 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 3",
                "points": 1.5,
                "status": "partial",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "92 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "dependency_advisories",
            "band": "excellent",
            "name": "Dependency advisories",
            "note": "Matched the npm:tapsmith@0.4.0 runtime dependency closure — what installing the published package pulls in — 203 packages. Reachability is not analyzed.",
            "notes": [
              {
                "code": "advisories_scope_published",
                "params": {
                  "package": "npm:tapsmith@0.4.0",
                  "assessed": 203
                }
              },
              {
                "code": "advisories_reachability",
                "params": {}
              }
            ],
            "value": 88,
            "inputs": {
              "source": "osv",
              "advisories": 1,
              "affected_packages": 1,
              "assessed_packages": 203,
              "unassessed_packages": 0,
              "affected_by_severity": "moderate 1",
              "direct_affected_packages": 0
            },
            "components": [
              {
                "key": "direct_dependencies_free_of_known_advisories",
                "name": "Direct dependencies free of known advisories",
                "detail": "no direct dependency carries a known advisory",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "no_direct_advisories",
                    "params": {}
                  }
                ],
                "max_points": 35
              },
              {
                "key": "indirect_dependencies_free_of_known_advisories",
                "name": "Indirect dependencies free of known advisories",
                "detail": "1 affected: @hono/node-server 1.19.14 (moderate 5.9)",
                "points": 13.2,
                "status": "partial",
                "details": [
                  {
                    "code": "advisories_affected",
                    "params": {
                      "count": 1,
                      "packages": "@hono/node-server 1.19.14 (moderate 5.9)"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "no_advisories_left_outstanding",
                "name": "No advisories left outstanding",
                "detail": "no advisory has been public longer than 90 days",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "advisories_none_stale",
                    "params": {
                      "days": 90
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "malicious_dependencies",
            "band": "excellent",
            "name": "Malicious dependencies",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "source": "osv",
              "meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
              "packages": [],
              "red_flag": false,
              "assessed_packages": 203,
              "malicious_packages": 0,
              "direct_malicious_packages": 0,
              "withdrawn_malicious_packages": 0,
              "installable_malicious_packages": 0
            },
            "components": [
              {
                "key": "no_dependency_reported_as_a_malicious_package",
                "name": "No dependency reported as a malicious package",
                "detail": "no dependency is reported as a malicious package",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "no_malicious_dependencies",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 2
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 81,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.979,
              "agent_instruction_files": [
                "CLAUDE.md",
                "docs/agents.md"
              ],
              "agent_instruction_max_bytes": 8640
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md, docs/agents.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md, docs/agents.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "95 of 97 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 95,
                      "sampled": 97
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 80,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "Cargo.lock",
                "package-lock.json"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [
                "packages/tapsmith/tsconfig.json",
                "test-app/tsconfig.json",
                "website/tsconfig.json"
              ],
              "agent_commit_share": 0.87,
              "toolchain_manifests": [
                "agent/app/build.gradle.kts",
                "agent/build.gradle.kts",
                "packages/tapsmith-core/Cargo.toml"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "agent/app/build.gradle.kts, agent/build.gradle.kts, packages/tapsmith-core/Cargo.toml (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "agent/app/build.gradle.kts, agent/build.gradle.kts, packages/tapsmith-core/Cargo.toml"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": "eslint.config.mjs",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "eslint.config.mjs"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "packages/tapsmith/tsconfig.json, test-app/tsconfig.json, website/tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "packages/tapsmith/tsconfig.json, test-app/tsconfig.json, website/tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "87 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 87,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 97,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 332289,
              "source_files_sampled": 388,
              "oversized_source_files": 18
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "TypeScript (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "TypeScript"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "18/388 source files over 60KB",
                "points": 52.4,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 388,
                      "oversized": 18
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "moderate",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "example_dirs": [],
              "has_mcp_signal": true,
              "api_schema_files": [
                "packages/tapsmith-core/vendor/mitmproxy_ipc.proto",
                "proto/tapsmith.proto"
              ]
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": "packages/tapsmith-core/vendor/mitmproxy_ipc.proto, proto/tapsmith.proto",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "packages/tapsmith-core/vendor/mitmproxy_ipc.proto, proto/tapsmith.proto"
                    }
                  }
                ],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "npm package 'website' points at a different repository (https://github.com/akoenig/node-website); excluded from ecosystem scoring",
    "Could not fetch crates package 'tapsmith-core' from its registry",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-23T20:14:30.426588Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/s/samsmithyeah/tapsmith.svg",
  "full_name": "samsmithyeah/tapsmith",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

Scores are signals, not warranties. They reflect publicly visible practices on GitHub — not a code audit, and not a security guarantee.

Missing data is excluded and weights renormalized, never scored as zero. Methodology is versioned and open: metrics v1.13.0, schema v0.27.0 — full methodology · metrics wiki.

How one result sits in the wider record: aggregate statisticsnpm.