Skip to content

fix(core): the task-surface scanner resolves computed constants, or stops - #244

Merged
stormer78 merged 1 commit into
mainfrom
fix/task-surface-scanner
Sep 14, 2026
Merged

stormer78 merged 1 commit into
mainfrom
fix/task-surface-scanner

Conversation

@stormer78

Copy link
Copy Markdown
Contributor

The bug, and why it was worth chasing

sync-task-surface.mjs only ever matched a string literal. vta-sdk increasingly doesn't write one — it derives the constant from the generated payload type, so the URI appears nowhere in the source:

pub const JOIN_REQUEST_MANIFEST_TYPE: &str =
    <manifest::v0_1::Payload as trust_tasks_rs::Payload>::TYPE_URI;

Nineteen constants are already in that form. The scanner saw none of them, and the way it failed is what makes this worth fixing rather than noting: the task was simply absent from the snapshot, and tests/task-surface.mjs reports any URI this library calls that's missing from it as a task the SDK does not have — its wording for a typo or a dropped task.

So a scanner limitation is indistinguishable from a live version-left-behind. It was mistaken for one, by me, earlier today: vtc/join-requests/manifest/0.1 in vtc/membership.ts read as a dead call. It isn't — vta-sdk still exports it and vtc-service still dispatches it (ManifestVersion::V0_1, trust_tasks/mod.rs:226). The next tasks:sync would have produced the same false finding again.

Resolving

Follows pub use trust_tasks_rs::specs::… within a file and reconstructs the URI from the module path: segments snake_case → kebab-case (join_requestsjoin-requests), v0_10.1. Braced groups resolve each name, including across the wrap rustfmt applies to a long one.

A pub use reaching inside a version module is importing types, not aliasing a spec — …::manifest::v0_2::{VettingRequirements, Branding} names two structs — so a path carrying a vN_M segment registers no aliases. Without that rule those struct names become spec modules and resolve to invented URIs.

Stopping

The more important half. A &str constant the script cannot turn into a URI is now fatal, naming the file, the declaration line and the constant:

Cannot resolve 1 `&str` constant(s) to a task URI:
  src/p.rs:2  ORPHAN_TYPE — no `pub use trust_tasks_rs::specs::…` in this file brings `nowhere` into scope

Writing the snapshot without it is what turned a limitation into something that read as a finding. Refusing to write is the scanner saying "I do not understand this", which is the true statement. include_str! / concat! constants are recognised as not-a-task so the stop doesn't fire on them.

The check that says the resolver is right

Re-syncing the same SDK the committed snapshot came from loses nothing — all 245 tasks survive — and gains eleven, ten of which are genuine SDK additions since 0.35 (the vetting family, audit/verify/0.1, join-requests/manifest/0.2). Agreeing with the literal era across 245 entries is stronger evidence than any fixture: it says the resolver reproduces what a human wrote by hand, rather than merely producing plausible strings.

task-surface.json is deliberately untouched here. The snapshot is of a published vta-sdk and refreshing it is its own deliberate act; this commit only makes that act correct when someone performs it.

Tests

Eight, driving the script as a subprocess against fixture SDK trees — what went wrong was end-to-end (what lands in the file, and what the exit code is), and neither is visible from importing a helper. They cover the resolution forms, the version-module rule, literal constants with and without a wrap and a #[deprecated], and the stop itself — including that a failed run leaves the existing snapshot on disk untouched.

npm test --workspace @openvtc/pnm-core — 649 pass.

…tops

`sync-task-surface.mjs` only ever matched a string literal:

    pub const TASK_ACL_GRANT_0_1: &str = "https://trusttasks.org/spec/acl/grant/0.1";

`vta-sdk` increasingly does not write one. It derives the constant from the
generated payload type instead, so the URI appears nowhere in the source:

    pub const JOIN_REQUEST_MANIFEST_TYPE: &str =
        <manifest::v0_1::Payload as trust_tasks_rs::Payload>::TYPE_URI;

Nineteen constants are already in that form. The scanner saw none of them, and
the way it failed is the reason this is worth fixing rather than noting: the
task was simply **absent** from the snapshot, and `tests/task-surface.mjs` then
reports any URI this library calls that is missing from it as a task *the SDK
does not have* — which is its wording for a typo or a task that was dropped.

So a scanner limitation is indistinguishable from a live version-left-behind.
It was mistaken for one: `vtc/join-requests/manifest/0.1` was read as a dead
call in `vtc/membership.ts`, and it is not — vta-sdk still exports it and
vtc-service still dispatches it (`ManifestVersion::V0_1`). The finding cost an
investigation before it was recognised as a false one, and the next `tasks:sync`
would have produced it again.

## Resolving

The scanner now follows `pub use trust_tasks_rs::specs::…` within a file and
reconstructs the URI from the module path: segments snake_case → kebab-case
(`join_requests` → `join-requests`), `v0_1` → `0.1`. Braced groups resolve each
name, including across the wrap rustfmt applies to a long one.

A `pub use` that reaches *inside* a version module is importing types, not
aliasing a spec — `…::manifest::v0_2::{VettingRequirements, Branding}` names two
structs — so a path carrying a `vN_M` segment registers no aliases. Without that
rule those struct names become spec modules and resolve to invented URIs.

## Stopping

The other half, and the more important one: a `&str` constant this script cannot
turn into a URI is now **fatal**, naming the file, the declaration line and the
constant. Writing the snapshot without it is what turned a limitation into
something that read as a finding; refusing to write is the scanner saying "I do
not understand this", which is the true statement. `include_str!` and `concat!`
constants are recognised as not-a-task so the stop does not fire on them.

## What it changes, checked against the old snapshot

Re-syncing the same SDK the committed snapshot came from loses **nothing** —
every one of its 245 tasks survives — and gains eleven, ten of which are real
SDK additions since 0.35 (the vetting family, `audit/verify/0.1`,
`join-requests/manifest/0.2`). That is the check that says the resolver agrees
with the literal era rather than merely producing plausible strings.

`task-surface.json` itself is deliberately untouched here: the snapshot is of a
*published* vta-sdk and refreshing it is its own deliberate act, which this
commit only makes correct when someone does it.

Eight tests drive the script as a subprocess against fixture SDK trees, because
what went wrong was end-to-end — what lands in the file, and what the exit code
is — and neither is visible from importing a helper.

Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
@stormer78
stormer78 merged commit 4d8cfd1 into main Sep 14, 2026
4 checks passed
@stormer78
stormer78 deleted the fix/task-surface-scanner branch September 14, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant