v0.1.0-rc.13
Pre-release
Pre-release
·
104 commits
to main
since this release
Added
surveys: new top-level domain for answering pending Toptal surveys
acrosscore/cli/mcp(#671). A talent can now list, answer,
and leave free-text feedback on pending surveys (e.g.INTERVIEW_ENDED
post-interview feedback,NPS,ENGAGEMENT_ENDED) without switching to
the Toptal portal. All three ops are hand-authored against the
mobile-gateway surface and route through Track 1 wire-shape snapshots
(each op is in the codegen-exclusion list, so no generated Zod schema
exists). The two write ops are consent-gated behind a new ADR-009
survey-submissionconsent domain (--consent-survey-submission/
surveySubmissionConsentIssued, the 5th domain), since both are
irreversible (there is no un-answer wire op) and route content to a third
party.surveys.list: read-onlyPendingSurveysquery (#672). Surfaces
each pending survey'sid,kind,title,isMandatory,
alreadyAnswered, andquestions[](each withid,label,note,
inputType, and selectableanswers[]) — everything an answer flow
consumes. Core:surveys.list(token). CLI:ttctl surveys list [-o pretty|json|yaml]. MCP:ttctl_surveys_list(read-only, dryRun-capable).
Wire-shape disposition: Schema/contract rule triggered (new
hand-authored op;Survey.kindandSurveyQuestion.noteare
Unknown-typed in the synthesized SDL); Track 1 (committed
packages/e2e/src/wire-snapshots/PendingSurveys.snapshot.json, captured
from real wire data). Validated live (TTCTL_E2E=1, two runs) via
packages/e2e/src/88-surveys-list.e2e.test.ts; the live shape matched
the projectedSurvey[]contract.surveys.submit: answer a pending survey viaSubmitSurvey
(#673). Resolveskindand per-question answer-option ids from the
pending list, so the caller supplies only<surveyId>and
<questionId>=<value>pairs. Core:surveys.submit(token, fields, consent, options)(consent gate, then resolve kind and option ids from
PendingSurveys, then the mutation, mappingUSER_ERRORonerrors[]
orsuccess:false). CLI:ttctl surveys submit <surveyId> --answer <qid>=<value>(repeatable)--consent-survey-submission. MCP:
ttctl_surveys_submit(destructiveHint, consent literal, zero-network
dryRunpreview). Wire-shape disposition: Schema/contract rule
triggered (hand-rollingSurveyAnswerInputis the inference act);
Track 1 (committedSubmitSurvey.snapshot.json). Validated via the
always-on safe paths inpackages/e2e/src/89-surveys-submit.e2e.test.ts
(consent-missing refusal andNOT_FOUNDresolution, both exercising
live bearer auth and the gatewayPendingSurveysread) plus a live
round-trip (2026-05-29) that submitted a realINTERVIEW_ENDEDsurvey
and confirmed it dropped out ofpendingSurveys; the gated DESTRUCTIVE
positive path (TTCTL_E2E_SUBMIT_SURVEY) automates the real submit for
opt-in operators.surveys.feedback: free-text feedback viaAddSurveyFeedback
(#674). Mirrorssubmit, and accepts an explicit--kindto reach a
non-pending survey (e.g. already-answered — the drained-account escape
hatch). Reuses thesurvey-submissionconsent domain (no consent or ADR
change). Core:surveys.addFeedback(...)sends the portal-shape{ kind, surveyId, feedback }over the mobile gateway. CLI:ttctl surveys feedback <surveyId> --text <text>. MCP:ttctl_surveys_feedback
(destructiveHint, consent literal,dryRunpreview). Wire-shape
disposition: Schema/contract rule triggered; Track 1 (committed
AddSurveyFeedback.snapshot.json). Satisfied by a capture-based
disposition rather than a fresh live round-trip — routing irreversible
third-party feedback is the exact harm the consent gate guards, and the
test account had no pending surveys. The{ kind, surveyId, feedback }
wire shape is established from the portalAddSurveyFeedbackcapture
(proveskindexists on the input type), the mobileAddFeedbackToSurvey
capture (omitskind, proving it optional on the shared input type), and
the #673 live transcript (the siblingsurveys.*op accepts the
kind-bearing portal shape on the gateway). The always-on safe paths in
packages/e2e/src/90-surveys-feedback.e2e.test.tsexercise the live wire
now; the gated positive path (TTCTL_E2E_ADD_SURVEY_FEEDBACK) refreshes
the snapshot on first natural survey availability.
profile.employment.reportingToAutocomplete: server-vetted autocomplete
forEmployment.reportingTo(#468). Read-only wrapper over the
talent-profileGET_REPORTING_TO_AUTOCOMPLETEquery — given a name prefix,
returns the suggestions Toptal will accept for thereportingTofield. A
min-length prefix gate (whitespace-trimmed) fires BEFORE any profile-id
resolution or wire call. Core:
profile.employment.reportingToAutocomplete(token, prefix, options?). CLI:
ttctl profile employment reporting-to-autocomplete <prefix> [--limit N].
MCP:ttctl_profile_employment_reporting_to_autocomplete. Wire-shape
disposition: Schema/contract rule triggered (new hand-authored op under
packages/core/src/services/profile/employment/**, in
TALENT_PROFILE_KNOWN_UNTRUSTED_OPS); Track 1. Validated live
(TTCTL_E2E=1, 2/2) via
packages/e2e/src/87-profile-employment-reporting-to-autocomplete.e2e.test.ts
(HTTP 200, no GraphQL errors, parses correctly); the wire-shape snapshot is
not yet captured — the test account returned empty ([]) for every
candidate prefix (the account-feature-gated family), so
assertWireShapeStableauto-captures on the first run that yields a
suggestion.
Fixed
profile.skills.add-connection: accept base64-encoded Relay node ids
(#646). Regression from rc.12'sconnectionTypetrim (#626): the
client-sideinferConnectionTypeFromIdcross-check demanded the decoded
V1-{Type}-NNNform, but the canonical wire shape returned by every
*.listtool (and sent by the SPA) is the encoded base64 form
(VjEtRW1wbG95bWVudC0xMjM0NQ==). Ids piped fromskills.list/
employment.list/education.list/certifications.list/
portfolio.listwere rejected client-side withVALIDATION_ERRORbefore
the wire call, so no workingconnectionIdwas reachable end-to-end. Fix
(Approach B, decode-then-fall-back-to-raw): a newdecodeRelayNodeId
helper base64-decodes behind a printable-ASCII gate (encoded ids decode to
the Relay-shaped string; raw ids decode to non-printable noise and fall
through to the raw path), so both the encoded canonical form and the
decoded back-compat form cross-check correctly. The wire payload still
ships the caller's original input verbatim — no transformation. Sibling
description sweep across theadd-connectionandremove-connectionCLI
help and MCP tool descriptions clarifies that*.listtools return the
encoded form. Wire-shape disposition: Schema/contract rule triggered
(touchespackages/core/src/services/profile/skills/**), but this is a
client-side validator widening — theAddProfileSkillSetConnectionInput { skillSetId, connectionId }wire shape is unchanged; Track 1
(addProfileSkillSetConnectionsnapshot capture remains the pre-existing
deferred gap from #462 / #626).