A job claim carrying text that cannot be read as text stopped the print lane. It is now refused like any other malformed job and the lane goes on.
What was wrong
A claim that named its job but carried an unpaired surrogate escape (for example \ud800) in the title, in another text field the agent reads, or in a member name threw while it was being read. There was no stand-in to answer with, so the job was neither refused nor printed and the lane stalled on it.
A member name that was not valid UTF-8 was silently skipped by the serializer, so such a job would have been printed with that member ignored.
What changes
Such a claim is refused: history shows RECEIVED then FAILED with a fixed reason ending "No bytes were submitted", nothing is downloaded or printed, and the next job is taken.
Only a job whose own identifier is the unreadable text still cannot be answered, which is the documented "names no job" case.
A response that offers no job is an empty claim, whatever names it carries.
What does not change
PrintWorker and the whole Windows layer are untouched. SUBMITTING is recorded before Windows is asked; FAILED means Windows was never asked; an interrupted submission is OUTCOME_UNKNOWN.
Verification
Head 9715c4f on release/2.0 at 6ad3001.
build/Verify.ps1 passed on that head: 968 Core, 1,523 Windows runtime and command line, 352 presentation tests, none failed; Core 100% of 2,169 lines; coverage gate passed.
Review (the reviewer who found the defect)
ca8d3eb: Verdict on ca8d3eb: 0 blockers, 0 should-fix, 5 nits. Nine mutations of the reviewer's own, all caught by tests. The reviewer judged the author's four departures from the proposed fix correct, one of them necessary.
The head merged is ca8d3eb replayed onto 6ad3001; git range-diff e2ca086..ca8d3eb 6ad3001..9715c4f reports both patches identical.
Left open, to be recorded in the audit (nits)
Worst-case cost for a hostile 2 MiB response from the server rose (up to about 8 seconds and 1.6 GiB of short-lived allocation; a submitter cannot reach it). Reading each object's names once would remove it.
A name beside the job refuses an intact job, stricter than needed.
Test rows put the unreadable name first only; two document sentences are slightly too broad; one comment in the realtime channel is now untrue for an unreadable name.
The queued-job preview is uneven for such text (display only); the realtime frame reader has the same pattern (a reader failure there reconnects).
A job claim carrying text that cannot be read as text stopped the print lane. It is now refused like any other malformed job and the lane goes on.
**What was wrong**
- A claim that named its job but carried an unpaired surrogate escape (for example `\ud800`) in the title, in another text field the agent reads, or in a member name threw while it was being read. There was no stand-in to answer with, so the job was neither refused nor printed and the lane stalled on it.
- A member name that was not valid UTF-8 was silently skipped by the serializer, so such a job would have been printed with that member ignored.
**What changes**
- Such a claim is refused: history shows RECEIVED then FAILED with a fixed reason ending "No bytes were submitted", nothing is downloaded or printed, and the next job is taken.
- Only a job whose own identifier is the unreadable text still cannot be answered, which is the documented "names no job" case.
- A response that offers no job is an empty claim, whatever names it carries.
**What does not change**
- `PrintWorker` and the whole Windows layer are untouched. SUBMITTING is recorded before Windows is asked; FAILED means Windows was never asked; an interrupted submission is OUTCOME_UNKNOWN.
**Verification**
- Head `9715c4f` on `release/2.0` at `6ad3001`.
- `build/Verify.ps1` passed on that head: 968 Core, 1,523 Windows runtime and command line, 352 presentation tests, none failed; Core 100% of 2,169 lines; coverage gate passed.
**Review (the reviewer who found the defect)**
- `ca8d3eb`: `Verdict on ca8d3eb: 0 blockers, 0 should-fix, 5 nits.` Nine mutations of the reviewer's own, all caught by tests. The reviewer judged the author's four departures from the proposed fix correct, one of them necessary.
- The head merged is `ca8d3eb` replayed onto `6ad3001`; `git range-diff e2ca086..ca8d3eb 6ad3001..9715c4f` reports both patches identical.
**Left open, to be recorded in the audit (nits)**
- Worst-case cost for a hostile 2 MiB response from the server rose (up to about 8 seconds and 1.6 GiB of short-lived allocation; a submitter cannot reach it). Reading each object's names once would remove it.
- A name beside the job refuses an intact job, stricter than needed.
- Test rows put the unreadable name first only; two document sentences are slightly too broad; one comment in the realtime channel is now untrue for an unreadable name.
- The queued-job preview is uneven for such text (display only); the realtime frame reader has the same pattern (a reader failure there reconnects).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The JSON parser accepts, as valid JSON, text it cannot afterwards turn into
a string: a surrogate escape without its partner and bytes that are not
UTF-8. The claim reader asked for member names and for five text members
outside the serializer, and for such text those calls throw
InvalidOperationException. That is not a protocol violation and carries no
stand-in, so a job that named itself was neither refused nor answered: the
lane stopped and the server offered the same job again.
The member lookups no longer fail on a name that is not readable text; such
a name is none of the contract's. A text member that cannot be read is read
as absent, so the stand-in leaves it empty and nothing is substituted. A
claim that offers a job is then refused, with the stand-in, when a member
name is not readable text in an object the agent reads members from: the
response, the job, its options or its media selection. Without that rule
the outcome depended on spelling, because the serializer fails on an
unpaired escape in an unknown name and skips a name that is not UTF-8. A
text member the agent reads was already refused by the serializer once the
job could be identified. Inside a field the agent does not read, unreadable
text is ignored with the rest of the field, and a response that offers no
job is an empty claim.
The reliability rule is unchanged: a refused job is recorded RECEIVED and
then FAILED with nothing downloaded and Windows never asked.
A claim whose job identifier is itself unreadable still names no job and
stops the lane, as documented for any claim without a usable identifier.
Each unreadable name costs one thrown exception each time it is looked at.
Measured on the real reader: options stuffed with such names inside the
server's 2,000-character cap (170 names) are refused in under a
millisecond; a response the server alone fills to 2 MiB with them (185,000
names) is refused in about 0.8 s when they sit beside the job and about 2 s
when they sit in the job.
The fake print server now queues claim bodies as bytes, so a test can offer
a body that is not text.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
The threat model, the realtime notes and the changelog said that a job
which names itself with one usable identifier is always refused, and that
only a claim naming no job stops a device's queue. Until the previous
commit that was not true of a claim carrying an unpaired surrogate escape
or bytes that are not UTF-8 in its title or in a member name.
They now state the rule as the code has it: such text is refused in a text
member the client reads and in a member name beside the job, in the job, in
its options or in its media selection; it is ignored inside a field the
client does not read; an unreadable display member is left empty in the
refused job's record; and a job identifier that cannot be read is one of
the ways a claim names no job.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
A job claim carrying text that cannot be read as text stopped the print lane. It is now refused like any other malformed job and the lane goes on.
What was wrong
\ud800) in the title, in another text field the agent reads, or in a member name threw while it was being read. There was no stand-in to answer with, so the job was neither refused nor printed and the lane stalled on it.What changes
What does not change
PrintWorkerand the whole Windows layer are untouched. SUBMITTING is recorded before Windows is asked; FAILED means Windows was never asked; an interrupted submission is OUTCOME_UNKNOWN.Verification
9715c4fonrelease/2.0at6ad3001.build/Verify.ps1passed on that head: 968 Core, 1,523 Windows runtime and command line, 352 presentation tests, none failed; Core 100% of 2,169 lines; coverage gate passed.Review (the reviewer who found the defect)
ca8d3eb:Verdict on ca8d3eb: 0 blockers, 0 should-fix, 5 nits.Nine mutations of the reviewer's own, all caught by tests. The reviewer judged the author's four departures from the proposed fix correct, one of them necessary.ca8d3ebreplayed onto6ad3001;git range-diff e2ca086..ca8d3eb 6ad3001..9715c4freports both patches identical.Left open, to be recorded in the audit (nits)
🤖 Generated with Claude Code