Production readiness · trustweave · 2026-09-06

TrustWeave Readiness Reassessment

Working tree at a41d482a, 5 commits ahead of origin Rubric identical to the 2026-09-05 assessment SaaS excluded
6.6/ 10
was 6.9 on 2026-09-05

Not releasable as it stands. The GA core is close, but the pipeline that would prove it has been red for two weeks and five verified defects sit in shipped code.

The drop is not a regression in the code that the previous round scored. That round ran nothing. This one ran the build, lint, ABI check and the full test suite, and read the CI history. The suite is green. The lint gate is not, and it runs first, so no CI evidence exists for anything added since August 23.

Scores by category

Category09-0509-06ΔWhy it moved
Security and access control8.57.5−1.0Federation chain verified backwards with unsigned statements accepted; Verifiable Intent L3 tokens never checked for audience or nonce; round-13 findings 01 and 02 still open. Transport gating and signing enforcement credited.
Observability and diagnosability5.05.0035 of 777 main-source files use a logger; 648 broad catches; 6 empty catches. Nothing changed.
Reliability and scale7.56.5−1.0This diff adds a FileWallet listing failure for relative paths, a filter that throws mid-iteration, cloud listings that abort on a concurrent delete, and an O(N) statistics path. Three sibling protocols still keep unbounded session maps.
Configuration and data7.57.0−0.5Stale ServiceLoader entries for optimism and zksync break anchor discovery; the new deployment policy is enforced by three factories and bypassed by the fourth.
Deployment and release5.56.0+0.5ABI validation, Kover, SBOM, mandatory signing and provenance attestation now exist and the ABI check passes locally. Capped: CI red since 08-23, 218 local lint violations, ABI dumps untracked, no release ever published.
Testing and documentation7.57.50Suite executed and green (3790 tests, 87 modules). 26 modules still have no tests; the federation verifier has no positive-path test; the checkout chain test was deleted rather than fixed.
Overall6.96.6−0.3

What was actually run

Gradle test
3790 passed · 0 failed
443 suites, 87 modules, 15 skipped, 6 m 46 s
checkKotlinAbi
passed
105 ABI dumps, all untracked
ktlintCheck
218 violations
13 files; CI runs this step first
CI on main
red since 08-23
run 33264669629 fails at lint
Reference wallet
70 / 70 · tsc clean
vitest, Node WebCrypto
Releases
none
tag v0.7.0, no artifact or attestation

Blockers

Each of these was re-verified in the source after the scanning agents reported it. Fix all six before tagging.

  1. B1

    CI gate has been red for two weeksconfirmed

    Every ci.yml run on main since 2026-08-23 fails at the lint step, before build or test. The working tree adds 218 more violations in 13 files. The ABI, coverage and SBOM steps added in this diff have never executed anywhere but this laptop.

    .github/workflows/ci.yml:56 · trust/dsl/TrustWeaveFactory.kt · anchors/plugins/indy · did/plugins/peer
  2. B2

    Two anchor plugins register classes that do not existconfirmed

    The optimism and zksync service files still name org.trustweave.chain.* classes; the code lives under org.trustweave.anchor.*. ServiceLoader throws while iterating, so any classpath containing either jar loses discovery of every provider after the broken entry. Arbitrum and base were fixed in this diff; these two were missed.

    anchors/plugins/optimism/src/main/resources/META-INF/services/… · anchors/plugins/zksync/…
  3. B3

    Federation trust chains are verified backwardsconfirmed

    verifyChain checks statement i+1 with statement i's keys, the reverse of OpenID Federation section 10.2, and never checks the leaf's signature at all. The parser also accepts alg=none. The only chain tests cover empty, expired and unparseable inputs, so a real chain has never been shown to pass. A real chain fails; an attacker's unsigned leaf listing the anchor key passes.

    credentials/plugins/openid-federation/…/TrustChainResolver.kt:142 · EntityStatementJwtProcessor.kt:51
  4. B4

    FileWallet cannot list with a relative storage pathconfirmed

    readRecord compares an absolute, normalised path against the raw Files.list entry. Path equality is textual, so any relative or dotted storagePath makes every list, query and statistics call throw after store succeeded. Tests only use @TempDir. Introduced by this diff.

    wallet/plugins/file/…/FileWallet.kt:403 · FileWalletFactory.kt:69
  5. B5

    Verifiable Intent payment tokens are replayable and budgets are reported as checkedconfirmed

    Audience and nonce are checked for L2 only; verifyL3 has no expected values, while the Python reference checks expected_l3_payment_aud and nonce. Budget, recurrence and reference constraints are still appended to checked (TW-R13-01), and a negative amount under a max-only range still passes (TW-R13-02).

    credentials/plugins/verifiable-intent/…/ChainVerifier.kt:96,360 · ConstraintChecker.kt:89,115
  6. B6

    The release controls cannot see this treeconfirmed

    444 changed paths and the 105 ABI dumps are uncommitted and five commits are unpushed. With explicit-path staging the dumps are easy to leave behind, and checkKotlinAbi then fails on every module. No release, signed artifact or attestation has ever been produced for v0.7.0.

    .github/workflows/release-evidence.yml:24 · */api/*.api

Needed, not blocking

  1. N1

    The revoked filter throws instead of filteringconfirmed

    list(CredentialFilter(revoked = false)) raises IllegalStateException on the first credential that carries a status entry, and no factory accepts a WalletStatusResolver to make it answerable.

    wallet/wallet-core/…/StoredCredentialRecord.kt:40
  2. N2

    Cloud and database listing paths abort or scale linearlyplausible

    A concurrent delete or one corrupt object fails the whole cloud listing; statistics download every object; DatabaseWallet.getStatistics now materialises every row with no LIMIT.

    wallet/plugins/cloud/…/CloudWallet.kt:140 · DatabaseWallet.kt:1283
  3. N3

    Status-list server leaks exception textconfirmed

    Both public routes return e.message under INTERNAL_ERROR and catch CancellationException. Unchanged since round 13.

    credentials/plugins/status-list/server/…/StatusListRoutes.kt:66,104
  4. N4

    The plaintext-to-public-host gate covers two of six client familiesplausible

    Algorand, Cardano and the Indy proxy still send tokens over http:// to any host. Hostnames with underscores are refused as unparseable. Bitcoin throws a raw IllegalArgumentException where EVM wraps it.

    common/…/TransportSecurity.kt:34 · AlgorandBlockchainAnchorClient.kt:110 · IndyVdrProxyTransport.kt:45
  5. N5

    Session state is unbounded in three protocols and hard-fails in a fourthconfirmed

    oidc4vp, SIOP and CHAPI keep plain maps with no expiry. The new oidc4vci store throws an unchecked exception at 1000 offers. The federation resolver bounds depth but not breadth or cycles.

    credentials/plugins/oidc4vp/…/SessionStore.kt:22 · SiopV2Service.kt:100 · ExpiringExchangeStore.kt:40
  6. N6

    Observability is where it wasconfirmed

    35 of 777 main-source files log anything. 648 broad catches, 6 empty. No correlation-id or metrics guidance.

  7. N7

    26 modules ship main code with no testsconfirmed

    cheqd, ens, ion, plc, polygon, sol, venafi, salesforce, servicenow, chapi, anchor, status-list database, both registrar servers, wallet-services, starknet and nine example scenarios. The ABI gate now freezes APIs nothing exercises.

  8. N8

    Reference wallet flows regressed (demo scope)plausible

    The claim-key extension is written but no verifier reads it; consent defaults to sharing nothing, so the airspace gate denies valid holders; the recovery export cannot be restored; reset fails in the environment that shows the recovery screen; passkey enrollment rejects synced authenticators after creating them. Weighted lightly because the README disclaims production custody.

    reference-wallet/lib/wallet.ts:186,245,359 · app/present/page.tsx:53 · lib/custody/passkey.ts:94
  9. N9

    Docs workflow unpinned and weakenedconfirmed

    docs-check.yml still uses mutable action tags while the other two workflows are SHA-pinned; the module-name gate was removed; the workflow now runs all 24 example mains on any Kotlin change.

    .github/workflows/docs-check.yml:37
  10. N10

    Deployment policy has a bypass and admits nothingplausible

    TestkitWalletFactory ignores it; SUPPORTED_ONLY can construct no wallet because every catalogued plugin is experimental; PluginRegistry rejects the roughly 98 uncatalogued modules.

    testkit/…/TestkitWalletFactory.kt:17 · common/…/PluginRegistry.kt:221

Already production grade

  • Full suite green when run: 3790 tests, 0 failures; ABI check passes.
  • Binary-compatibility validation on every Kotlin module with a documented update procedure.
  • Remote publication refuses to run without a signing key; per-module CycloneDX SBOM attached.
  • Provenance attestation workflow; ci.yml and release-evidence.yml pinned to commit SHAs.
  • Plaintext to public hosts refused for EVM and Bitcoin, failing closed on DNS failure.
  • In-memory KMS refused outside dev/test; wallet deployment policy tested for three plugins.
  • Bounded, expiring oidc4vci stores; PKCE; SSRF guards; bounded response bodies.
  • module-maturity.md tiers every module; release-validation.md documents ABI, SBOM and signing.

Recommended sequence

  1. ktlintFormat, hand-fix the residue, get one green CI run on main so the new gates execute for the first time.
  2. Fix the two service files; add a ServiceLoader smoke test over distribution:all.
  3. Rewrite verifyChain in spec order, reject unsigned statements, add a positive-path test with real keys.
  4. Normalise walletDir in FileWallet; add a relative-path test.
  5. Port the L3 audience and nonce checks; split checked into enforced and acknowledged; reject negative and string amounts.
  6. Commit the ABI dumps with the code, push, tag, run release-evidence once and verify the attestation.
  7. Then N1 to N5 in order; N6 to N10 as hygiene.

Method and limits

Ran assemble, ktlintCheck, checkKotlinAbi and the full test task locally with three workers, plus tsc and vitest for the reference wallet. Fourteen review agents scanned the diff from complementary angles; every blocker and the load-bearing needed items were re-verified by reading the source, and B5 was checked against the Python reference implementation. Round-13 findings were re-checked in the tree.

Nothing was deployed or load-tested and no fix was applied. Items marked plausible rest on agent evidence not independently reproduced. Reference-wallet defects are weighted as demo scope. SaaS is out of scope. Machine-readable scores and findings sit beside this file as scores.json and findings.json.