The first step of the multi-server build: version 2 of the management pipe's contract, as types only. Nothing serves or sends it yet; the service, the command line and the companion are unchanged. Later steps implement the handlers, the pipe server and the clients against these types.
What is here (src/Qqq.PrintAgent.Windows/Management/, 68 files, one type each)
The envelope: ManagementRequest(V, Op, Server, Args), ManagementReply(V, Ok, Result, Error), ManagementError(Code, Message, Details), read only through ManagementJson.ParseRequest and ParseReply, which make the envelope checks; the serializer cannot read an envelope directly.
31 error codes that clients switch on, five with typed details.
30 operations in a table with each one's scope (computer or one server), kind (read, change, or a session change that answers busy), time limit, and whether it answers while the stored data is not ready.
An argument record per operation that takes arguments, and the results: the aggregated snapshot (the computer once, each server once), the server check with its stages and the presented certificate, sign-in, sign-out, enrollment, update preparation, removal, the traffic meter read.
ServerSelector: the pure rule the command line will use for --server.
Rules the wire enforces
No result or details type can carry a session credential, a device token, a cookie, an enrollment code or document content; one named exception, the sign-out reply's provider request. A structural test fails if a type gains a member that could.
Text a server supplied (an error's message, the approved account in identity_changed) is made printable and cut where the reply is built, by the one definition Core uses.
A request is refused for an unknown member, a repeated member at any depth, arguments on an operation that takes none, or a null in a list; a reply's unknown members are skipped, so a newer service can add one.
A request without v is recognized as a version 1 client.
Design record: docs/adr/0004-multi-server-runtime.md gains what two reviews of the contract settled (new section "Resolved while reviewing the pipe contract"): five codes for outcomes version 1 explains in text, last contact and a light traffic-meter read, a snapshot that never starts printer discovery, printers.discover, and how removal answers a retry.
Also: JobSnapshot gains EarlierPairing, written only when true, so version 1 output is byte for byte unchanged. Core's printable-text function becomes public (one word).
Tests: 372 cases; 67 golden files (a request and a reply per operation, a failure per code with details, two realistic snapshots) that must match the tables exactly, both ways.
Verification, local, on this head (on b868e9e): build/Verify.ps1 passed three times with no failing test: 766 Core, 1,001 Windows/command-line and 352 presentation tests, zero warnings; Core, command line and presentation 100%; Windows 74.4% (minimum raised from 69 to 73); the Management folder 410 of 410 lines.
Review: independent, three passes. The first found three should-fix items (repeated members inside arguments; five outcomes with no code; two things the companion reads with no home), the second one (server-supplied text bounded only by a comment); each was fixed as the reviewer proposed. The reviewer built the head and ran the contract tests.
The first step of the multi-server build: version 2 of the management pipe's contract, as types only. Nothing serves or sends it yet; the service, the command line and the companion are unchanged. Later steps implement the handlers, the pipe server and the clients against these types.
**What is here** (`src/Qqq.PrintAgent.Windows/Management/`, 68 files, one type each)
- The envelope: `ManagementRequest(V, Op, Server, Args)`, `ManagementReply(V, Ok, Result, Error)`, `ManagementError(Code, Message, Details)`, read only through `ManagementJson.ParseRequest` and `ParseReply`, which make the envelope checks; the serializer cannot read an envelope directly.
- 31 error codes that clients switch on, five with typed details.
- 30 operations in a table with each one's scope (computer or one server), kind (read, change, or a session change that answers `busy`), time limit, and whether it answers while the stored data is not ready.
- An argument record per operation that takes arguments, and the results: the aggregated snapshot (the computer once, each server once), the server check with its stages and the presented certificate, sign-in, sign-out, enrollment, update preparation, removal, the traffic meter read.
- `ServerSelector`: the pure rule the command line will use for `--server`.
**Rules the wire enforces**
- No result or details type can carry a session credential, a device token, a cookie, an enrollment code or document content; one named exception, the sign-out reply's provider request. A structural test fails if a type gains a member that could.
- Text a server supplied (an error's message, the approved account in `identity_changed`) is made printable and cut where the reply is built, by the one definition Core uses.
- A request is refused for an unknown member, a repeated member at any depth, arguments on an operation that takes none, or a null in a list; a reply's unknown members are skipped, so a newer service can add one.
- A request without `v` is recognized as a version 1 client.
**Design record**: `docs/adr/0004-multi-server-runtime.md` gains what two reviews of the contract settled (new section "Resolved while reviewing the pipe contract"): five codes for outcomes version 1 explains in text, last contact and a light traffic-meter read, a snapshot that never starts printer discovery, `printers.discover`, and how removal answers a retry.
**Also**: `JobSnapshot` gains `EarlierPairing`, written only when true, so version 1 output is byte for byte unchanged. Core's printable-text function becomes public (one word).
**Tests**: 372 cases; 67 golden files (a request and a reply per operation, a failure per code with details, two realistic snapshots) that must match the tables exactly, both ways.
**Verification**, local, on this head (on `b868e9e`): `build/Verify.ps1` passed three times with no failing test: 766 Core, 1,001 Windows/command-line and 352 presentation tests, zero warnings; Core, command line and presentation 100%; Windows 74.4% (minimum raised from 69 to 73); the Management folder 410 of 410 lines.
**Review**: independent, three passes. The first found three should-fix items (repeated members inside arguments; five outcomes with no code; two things the companion reads with no home), the second one (server-supplied text bounded only by a comment); each was fixed as the reviewer proposed. The reviewer built the head and ran the contract tests.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
ADR-0004 gives the management pipe a versioned contract: requests name the
server they act on, replies are typed, and clients switch on an error code
instead of matching text. This is that contract as types only, in
src/Qqq.PrintAgent.Windows/Management. Nothing serves or sends it yet, and
no existing behavior changes.
- Envelope: ManagementRequest, ManagementReply, ManagementError and
ManagementJson, the one serializer. Requests are read strictly and every
way an envelope can be wrong is told apart (too large, not JSON, not an
object, no version, another version, an unexpected or repeated member,
no operation, a malformed operation name, a malformed server, arguments
that are not an object). Replies skip members they do not know. The
text form of a request never shows its arguments and that of a reply
never shows its result.
- ManagementErrorCode: the 26 codes of the ADR's table, as text.
- ManagementOperations: the 28 operations with scope, kind, the service's
time limit, whether each answers while the stored data is not ready, and
the record its arguments and its result are read into; and Check, the
pure rule for whether a request names a server correctly.
- One argument record for each of the 18 operations that take arguments.
- Result records: the aggregated snapshot (computer once, each server
once), the compatibility check with its five stages and the refused
certificate, and the results of adding, removing, signing in and out,
enrolling, trust, update preparation and the job actions. Three error
codes carry typed details.
- ServerSelector: the pure resolution of the command line's --server.
JobSnapshot gains EarlierPairing, written only when true, so what version
1 sends for a job is byte for byte what it sent before; a test holds that.
Tests: 59 golden files (a request and a reply per operation, a failure per
code with details) that each round-trip through the typed records to the
same document and equal the examples built in code; the envelope
refusals; the two tables against the ADR's lists written out in the test;
and the mappings from Core's compatibility result, a refused certificate,
a Windows printer, the control state and an enrollment answer.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
A full identifier selects its server; the first eight or more characters
of one do when only one identifier begins that way; a name does, in any
letter case. A name or prefix that fits more than one server is ambiguous
and lists their identifiers; so is a value that is one server's name and
another's prefix. A prefix shorter than eight characters is refused as too
short. With no value the only server is selected, several servers require
one to be named, and no servers select nothing.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Two tests hold the rule from two sides. The structural one walks every
type a result or an error's details can contain and requires each member
to be plain text, a number, a boolean, a date, a list of those, or a
record of the contract or of a short list of reused snapshot records:
there is no free-form bag and no credential type anywhere in a reply. The
other serializes a fully populated example of every result and of every
code's details, built from a session credential, a stored pairing, a
stored session and an enrollment answer that carry canaries where the real
ones carry secrets, and requires the canaries to be absent.
The one exception ADR-0004 names is held to one place: the provider's
sign-out request is on the sign-out result and in no other reply, and that
result prints as fixed text.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
docs/DEVELOPMENT.md described the pipe as version 1 only. It now says that
version 2 exists as a contract in src/Qqq.PrintAgent.Windows/Management,
that nothing serves or sends it yet, and that its wire form is held by the
golden files, which change together with the record and its example.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
JobSnapshot, JobEventSnapshot and PrinterServerSync are reused by version 2
of the management pipe. Their times are text the service stored, not
instants the contract's date rule converts; the summaries now say so.
No behavior changes.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
ADR-0004 gains the outcomes version 1 explains only in text (not_connected,
server_unreachable, server_refused, cancel_refused, server_removing), the
details of identity_changed, serverSessionEnded on sign-out, lastContact,
the transport.get read for the traffic meter, a trust.get that never
probes, and the reading rules: repeated members, omitted arguments, what a
reply must contain, dates, and the version of a reply.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Reading: a member repeated at any depth is refused by the parser and by
both serializer options, so the envelope no longer keeps its own set of
names. Replies are read with required and nullable checks on, still
skipping unknown members; a member that may be null may be absent. A null
inside a list is refused. Arguments that are left out read as an empty
object. Dates are read only as ISO 8601 with a trailing Z or an offset.
Envelope: arguments, results and details are held as a ManagementPayload
whose text form is fixed, so none of them can land in a log line.
Table: five codes (server_removing, not_connected, server_unreachable,
server_refused, cancel_refused) and one operation (transport.get), typed
details for identity_changed and cancel_refused, serverSessionEnded on
sign-out, lastContact on a server, the origin and time of a remembered
certificate, and a record of its own for logs.setSettings.
Tests and golden files follow, with two further snapshots as a client
will see them: two healthy servers, and stored data that is not ready.
The envelope's payload type reaches every test of the contract, which is
why this is one commit.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Twenty-nine operations, the payload type, the two further snapshot
examples, and what is refused in both directions.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
The version 2 contract is covered line for line, which lifts the measured
figure for Qqq.PrintAgent.Windows to 74.15% (3085 of 4160 lines). The
minimum is that figure rounded down, less one point. The other three
assemblies stay at 100.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
QqqCompatibilityProblem.Printable is the one definition of text a server
supplied that is safe to show. The management pipe contract in the Windows
assembly needs the same definition for error messages and identity values,
so the function becomes public where it lives. Its behavior, its summary
and every caller are unchanged.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
ADR-0004 now says that the wire enforces the form of server-supplied text
(512 for any error message, 200 for an identity value, one definition in
Core); that a repeated servers.remove succeeds with removing again; that
the computer's printers carry the time they were discovered, the host
keeps the list at most 60 seconds old and printers.discover asks for a
fresh one; that transport.get answers with an empty list while the stored
data is not ready; that arguments for an operation that takes none are
refused; and that only a list the reader knows is checked for a null.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Error messages are made printable and cut at 512 by both failure
factories, and IdentityChangedDetails is built only by a factory that does
the same to both values at 200, with Core's Printable.
The envelope types are written by the serializer and refuse to be read by
it, naming ParseRequest and ParseReply, so the envelope checks cannot be
walked around. Arguments given to an operation that takes none are
refused by the routing check; an empty object is accepted. A null inside a
list is refused only in a list the record knows, so a later version's
member cannot make today's reader refuse a reply. A nullable member its
record marks as required stays required.
printers.discover is added (computer scope, read, 30 seconds, not while
the stored data is not ready) and the computer's snapshot carries
printersDiscoveredAt. transport.get answers while the stored data is not
ready. Which operations answer for a server that is being removed is a
rule on the operation's row: reads and a repeated servers.remove.
Tests and golden files follow: 30 operations, 67 golden files. The
serializer and the envelope tests are shared by every item, which is why
this is one commit.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Thirty operations, lists the record knows, the two parsing functions as
the only way to read an envelope, and the bound on error messages.
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.
The first step of the multi-server build: version 2 of the management pipe's contract, as types only. Nothing serves or sends it yet; the service, the command line and the companion are unchanged. Later steps implement the handlers, the pipe server and the clients against these types.
What is here (
src/Qqq.PrintAgent.Windows/Management/, 68 files, one type each)ManagementRequest(V, Op, Server, Args),ManagementReply(V, Ok, Result, Error),ManagementError(Code, Message, Details), read only throughManagementJson.ParseRequestandParseReply, which make the envelope checks; the serializer cannot read an envelope directly.busy), time limit, and whether it answers while the stored data is not ready.ServerSelector: the pure rule the command line will use for--server.Rules the wire enforces
identity_changed) is made printable and cut where the reply is built, by the one definition Core uses.vis recognized as a version 1 client.Design record:
docs/adr/0004-multi-server-runtime.mdgains what two reviews of the contract settled (new section "Resolved while reviewing the pipe contract"): five codes for outcomes version 1 explains in text, last contact and a light traffic-meter read, a snapshot that never starts printer discovery,printers.discover, and how removal answers a retry.Also:
JobSnapshotgainsEarlierPairing, written only when true, so version 1 output is byte for byte unchanged. Core's printable-text function becomes public (one word).Tests: 372 cases; 67 golden files (a request and a reply per operation, a failure per code with details, two realistic snapshots) that must match the tables exactly, both ways.
Verification, local, on this head (on
b868e9e):build/Verify.ps1passed three times with no failing test: 766 Core, 1,001 Windows/command-line and 352 presentation tests, zero warnings; Core, command line and presentation 100%; Windows 74.4% (minimum raised from 69 to 73); the Management folder 410 of 410 lines.Review: independent, three passes. The first found three should-fix items (repeated members inside arguments; five outcomes with no code; two things the companion reads with no home), the second one (server-supplied text bounded only by a comment); each was fixed as the reviewer proposed. The reviewer built the head and ran the contract tests.
🤖 Generated with Claude Code