Releases: Judgment-Pack/judgment-pack-gateway
Release list
gateway v0.7.0
Three changes to the adapters' Google Drive connection, one of them a decision of record, and one row of SPEC.md that states a behaviour the verifier had. The frozen corpus and the core module are as v0.6.0 has them.
What an operator must do
- A host that reads the catalog changes with this release. Drive's entry names
source-searchwhere it namedbrowser-picker; the methodpickis gone andsearchandselecttake its place; a selection answers withresourceIdwhere the chooser's answered withfileId. A host that expects the old entry refuses this release's catalog whole. So a desk moves to this release and changes how it chooses a Drive file in one change. - Every Drive connection is asked to connect again. A connection made by an earlier release is of the scope
drive.file. Its first request that needs Drive is answeredreconnect-required, and the person connects again.statusdoes not say so beforehand: it saysconnected, as it did. - A host may offer the new method,
files-prepare-google-document. Catalog v3 lists it for Drive. Nothing requires a host to offer it. - The owner's Google Cloud project changes. The consent screen's Data access lists
https://www.googleapis.com/auth/drivein place ofdrive.file; the Google Picker API is no longer needed, and the Google Drive API still is. Google restricts this scope: an owner who uses their own registration themselves, within their organization, or as a named test user needs no verification by Google; a registration offered to the public does. Public releases of this repository and of a desk carry no registration, as before.
A Drive connection is of the whole of a person's Drive (#189, ADR-0010)
A Drive connection asked for drive.file and opened Google's own chooser of files. Under that scope it saw the files it made and the files a person chose in the chooser, and no others. ADR-0010 decides otherwise, and this release builds the first three of its five determinations:
v0.6.0 |
v0.7.0 |
|
|---|---|---|
| Scope asked of Google | drive.file |
drive, and no other; a token of another scope is refused |
| How a file is chosen | Google's chooser, inside the consent | search, then select |
| Drive's methods | status, configure, connect, pick, poll, cancel, disconnect |
the same without pick, with search and select |
A storage listing's scope |
app-authorized-files |
account-files |
search takes { "query": "words" } and gives at most twenty files that adapter-drive would take, by what Drive says of each: with words, what Drive finds for them, in the order Drive gives them; without, what was changed last. select takes at most four IDs and gives a grant for each, for one read within five minutes. A grant says that the host asked to read the file; it does not say that a person chose it. adapter-drive reads as it did.
What a consent was for is recorded when it is given, in consent.json beside the connection's state, and again at every renewal: the connection, a digest of each token, and the scope. Every request that needs Drive is held to that record and not to what a renewal says. A connection without a record of a consent for drive for the tokens it holds is refused: a connection made by an earlier release, one whose tokens an earlier release replaced after a rollback, and one a process renewed and ended before it wrote the record. The state's own shape is unchanged, so an earlier release reads it and ignores the record.
Decided and not built. Determination 4: an update and a move to trash of a Drive file are to be held to the file's version, read immediately before the change, in place of a conditional request that Drive does not offer. Until it is built, both are refused with conditional-write-unavailable, as they were. This replaces, for Drive, one consequence of ADR-0005; it replaces nothing of ADR-0006.
A Google Doc made of a Word file, by Drive's conversion (#176)
The storage controls gain one method, for Drive alone: files-prepare-google-document. It takes a Word file (application/vnd.openxmlformats-officedocument.wordprocessingml.document, framed as one) with a name and, where given, a folder, and prepares a plan whose convertTo is google-document, so that a person sees what the file becomes before they confirm. The commit is one upload that asks Drive to convert, sent once and never again. Drive gives the document its ID; what was made is held to be a Google Doc by Drive's own answer, and where Drive made something else the plan says conversion-unconfirmed and names the file so that a person can find it. An ordinary create cannot ask for a conversion, and a conversion cannot be asked of anything but a Word file.
Tried once against a live Drive account on 2026-09-29: the plan was prepared with no confirmation asked, the commit completed in under three seconds with a target, and the listing showed the target as application/vnd.google-apps.document. ADR-0006's determination 6 left this to a contract and a review of its own; the contract is a section of docs/design/storage-files.md, and no decision record is added.
SPEC §4.1 states the verdict for a store root that cannot be read (#190)
One row: a store root that is a directory but cannot be read gives no verdict; the verifier refuses, as it does for a root that is not a directory. The row states what TestStoreRootShapes had asserted since before v0.4.0 and changes no program. It completes the table's three shapes of the root, as the three shapes of <root>/receipts below it were already stated.
A search of Drive by words asks for no order (#188)
Drive refuses an order asked of a search by words, and every files-list with words on Drive was answered provider-unavailable since v0.4.0. A search by words now asks for no order and comes in the order Drive gives it. A listing without words asks for Drive's order folder,name, as before.
To verify a download
sha256sum --check --ignore-missing checksums.txt
gh attestation verify <archive> \
--repo Judgment-Pack/judgment-pack-gateway \
--signer-workflow Judgment-Pack/judgment-pack-gateway/.github/workflows/release.yml \
--source-ref refs/tags/v0.7.0What was checked before this release was published:
| Check | Where |
|---|---|
| Everything CI asks of a commit, at the tagged commit | Linux, macOS, Windows |
| Every archive read: its files are the commit's, byte for byte; each program is the bytes the packer built, from the package of its name, for the archive's platform | all six archives |
The archive run: gateway version, and gateway conform on the corpus it carries |
Linux amd64 and arm64, macOS arm64, Windows amd64 |
| Three adapters started | Linux amd64 and arm64, macOS arm64 |
docs/releasing.md says how a release is made and what each check does not establish.
What this release establishes of Drive, and what not
One connection was tried against a live Drive account on 2026-09-29, with the programs of #189 and #188 and a registration made for it: the consent was granted for the scope asked; a search without words gave twenty files of four kinds; a search by one word found two files another client had made under drive.file; a listing of the root gave a page of folders; one file was read under a grant, and the grant was refused a second time; the consent was revoked at disconnect. That is one account on one day. Not tried: another account, a shared drive, an organization with an internal audience, a consent refused, a renewal of the token, a rollback.
- No update and no move to trash of a Drive file goes through: the try of
v0.6.0's controls found that Drive gives no ETag, and the refusal stands until determination 4 is built. That holds of a document made by conversion too: the controls make it and cannot move it to trash. - Of a conversion, one file on one account: not a conversion Drive refuses or leaves half done, an answer lost on the way, a shared drive, or a large file.
- That a live Tavily or Google Cloud account is accepted by the search source, as the notes of
v0.5.0andv0.6.0said. - That a desk takes this release: no desk is tested here, and a desk must change with the catalog.
- The
darwin/amd64andwindows/arm64archives are built and read, and run by nothing. - The adapters' tests run on Linux. No check reaches a platform account.
- The engine image is not published. CI builds it from every commit and never pushes it.
Review
#189 went through three rounds of the gateway's cross-vendor review regime, #176 through four, and #188 through one. Every record and disposition is on the pull requests. #190 is a clarification of one row, reviewed against its issue's acceptance criteria on the pull request.
gateway v0.6.0
Two changes to what the adapters do, and two to documents. The gateway's contract is unchanged: SPEC.md, the frozen corpus and the core module are as v0.5.0 has them.
What an operator must do
- A host that writes a request to the connection programs, to
adapter-airbyteor toadapter-mcpwrites each member's name as the documents write it. A request with a member named in another case (QUERYforquery) was read and is now refused. A request named as written is read as before. - A desk that takes this release's local plan carries
adapter-renderin its bundle. A desk takes a plan only where every program the plan names is in its verified bundle. One withoutadapter-renderrefuses the plan whole, and then has no local source at all. So a desk moves to this release and adds the program to its bundle in one change. A desk that stays onv0.5.0needs neither.
Adapters read a request's members by their names as written (#185)
Four readers of a request decoded it into a struct, refusing a member the struct does not know. Go's decoder matches a member's name to a field's without regard to case, so to it QUERY is query and is known; and where a request held both, it read the one that came last. The refusal of a name given twice did not see the second spelling.
| Reader | What it reads |
|---|---|
| the connection programs' two | every operation of gateway-connections, and the requests of adapter-drive, adapter-gmail and adapter-sources |
adapter-airbyte's |
its request |
adapter-mcp's |
its request. The arguments of a tool are the tool's, and their names are held to nothing |
Each now refuses a member that is not named as written, and one named twice in any spelling. The other adapters and the core read by exact names already.
Not covered, and stated in adapters/README.md: an operation that answers without reading its body, as every operation of a connection service the operator has blocked does; the line gateway-connections reads from its parent; and a document within a request, such as a Google service account's credential, which the library that uses it reads.
What the programs of v0.5.0 wrote into custody is read as before.
The desk's local plan names adapter-render (#179)
gateway-connections --local-plan gains one entry, so that a desk's gateway has a source render:
| Member | Value |
|---|---|
id |
render |
executable |
adapter-render |
args |
--max-output 6291456 |
shape |
command |
timeout |
30 |
connections |
false |
No rendering program is named, so a request for a PDF under the plan is refused as renderer-not-configured. A Word file is written by the adapter itself. The plan has ten sources.
Documents
- The form of a search's arguments and result is published (#183), as two JSON Schemas with an example of each kind of result, under
testdata/search. CI holds a result of each kind, written by the source in the same run, to the schema. They are in the repository and not in an archive. - How an issue is claimed and worked on (#184), in
CONTRIBUTING.md.
To verify a download
sha256sum --check --ignore-missing checksums.txt
gh attestation verify <archive> \
--repo Judgment-Pack/judgment-pack-gateway \
--signer-workflow Judgment-Pack/judgment-pack-gateway/.github/workflows/release.yml \
--source-ref refs/tags/v0.6.0What was checked before this release was published:
| Check | Where |
|---|---|
| Everything CI asks of a commit, at the tagged commit | Linux, macOS, Windows |
| Every archive read: its files are the commit's, byte for byte; each program is the bytes the packer built, from the package of its name, for the archive's platform | all six archives |
The archive run: gateway version, and gateway conform on the corpus it carries |
Linux amd64 and arm64, macOS arm64, Windows amd64 |
| Three adapters started | Linux amd64 and arm64, macOS arm64 |
docs/releasing.md says how a release is made and what each check does not establish.
What this release does not establish
- That a live Tavily or Google Cloud account is accepted by the search source, or what a live answer holds. No provider has been called with an account, as the notes of
v0.5.0said. - That a desk takes the plan: no desk is tested here. What the plan asks of one was established by running a desk's own reader on the plan.
- That a rendering program makes a good PDF, where an operator names one.
- The
darwin/amd64andwindows/arm64archives are built and read, and run by nothing. - The adapters' tests run on Linux. Of the adapters in an archive, three are started by the release checks and the rest by none. No check reaches a platform account.
- The engine image is not published. CI builds it from every commit and never pushes it.
Not in this release
The creation of a Google Doc from a Word file by Drive's conversion (#176) is reviewed and is not merged: it has not been tried against a Google account.
Review
#179, #183 and #185 each went through the gateway's cross-vendor review regime. Every record and disposition is on the pull requests. #184 changes a contributing guide.
The frozen corpus and SPEC.md are unchanged since v0.4.0: 30 canon vectors and 41 store vectors.
gateway v0.5.0
The first release of this repository that carries its programs, and the first made by its release workflow. Two candidates came before it, v0.5.0-rc.1 and v0.5.0-rc.2. It is built from the commit the second was built from.
What an operator must do
Nothing, to keep what v0.4.0 did. The gateway's contract is unchanged: SPEC.md and the frozen corpus are as v0.4.0 has them, and receiptVersion is what it was.
Three things an operator may notice:
- A released
gatewaynames its release.gateway versionprints it, and the MCP server reports the same asserverInfo.version. A build from a checkout still saysunversioned build. - Catalog v3 lists a provider under a second protocol,
web-search-v1. A host that knows onlyconnection-v1lists it as unsupported and calls nothing. - The adapters link two more modules,
golang.org/x/oauth2andcloud.google.com/go/compute/metadata.THIRD_PARTY_NOTICESnames them.
A release now carries the programs (#173, ADR-0008)
Releases up to v0.4.0 were a tag and notes. From this one, a release carries six archives, for Linux, macOS and Windows on amd64 and arm64. Each holds gateway, every program under adapters/cmd, SPEC.md, the corpus, the catalog and the licences.
To verify a download:
sha256sum --check --ignore-missing checksums.txt
gh attestation verify <archive> \
--repo Judgment-Pack/judgment-pack-gateway \
--signer-workflow Judgment-Pack/judgment-pack-gateway/.github/workflows/release.yml \
--source-ref refs/tags/v0.5.0What was checked before this release was published:
| Check | Where |
|---|---|
| Everything CI asks of a commit, at the tagged commit | Linux, macOS, Windows |
| Every archive read: its files are the commit's, byte for byte; each program is the bytes the packer built, from the package of its name, for the archive's platform | all six archives |
The archive run: gateway version, and gateway conform on the corpus it carries |
Linux amd64 and arm64, macOS arm64, Windows amd64 |
| Three adapters started | Linux amd64 and arm64, macOS arm64 |
docs/releasing.md says how a release is made and what each check does not establish.
Named web search connections (#180, ADR-0009)
A new source, web-search, read by adapter-sources, and a provider of the same name in gateway-connections. A connection is to Tavily or to Google Cloud Search grounding. A search gives links to read through web, not documents.
- Up to six named connections, each with a daily request budget that is reserved before the network is reached. Failed calls and connection tests count.
- Endpoints are fixed in the adapter. A caller supplies none.
- A connection is checked before a request and after its answer. An answer that arrives after the connection changed, or was blocked, is refused.
- A Google answer is a generated answer with links. The answer, the links, the queries and Google's attribution markup are kept apart, and an answer without links and attribution is refused. The markup is Google's: a consumer treats it as markup it did not write.
- The acquisition is under the existing HTTP receipt shape. Its statement names the request's parameters and is not the bytes sent.
No provider was called with an account. Every test answers from a local server or a stand-in. docs/web-search.md is the contract, and says what was tested.
adapter-render writes a Word file and a PDF (#168, #170, #174, under ADR-0006)
A new adapter, a bare source under the command shape. It reads a format, a title and content as a closed structure of blocks, and writes a version 1 render record that holds the file with its size and digest, so that a receipt's output commitment covers the file.
- A Word file is written by the adapter itself. The same content gives the same bytes from the same build. Microsoft Word was not available to open the file with; pandoc, LibreOffice and python-docx read it.
- A PDF is written by a rendering program the operator names with
--renderer. The program is handed the Word file of the same content and answers with the PDF. The adapter checks that the answer begins and ends as a PDF does; it does not open it. Without a program a PDF is refused asrenderer-not-configured. - No archive carries a rendering program, and nothing names the adapter yet: no engine configuration, image or desk plan. An operator adds the source.
docs/design/rendering.md is the contract.
Smaller changes
- The run of an operator's program has one home (#171). The code that runs the OCR program moved to a package of its own, and the rendering program is run from the same code. The document adapter behaves as it did, with one stated difference: page numbers are made into arguments before the run, where they were made after the deadline's check.
- A source's time bound, as the code has it (#177). Four places gave a figure for how long a source may run, and
SECURITY.mdgave a ceiling the gateway does not have. Each now says both figures and whose each is. - Design notes of what has shipped say so (#167).
Decided, and not built (ADR-0007, #172)
How an engine started from its configuration is to serve the adapters it ships, as services named in that configuration. Nothing in this release implements it.
What this release does not establish
- That a live Tavily or Google Cloud account is accepted, or what a live answer holds. The form of Google's source links, the size of its attribution markup and the models that support grounding are as its documentation states them, not as observed.
- That a rendering program makes a good PDF. The adapter vouches for the Word file it wrote, and for nothing of the step after.
- The
darwin/amd64andwindows/arm64archives are built and read, and run by nothing. - The adapters' tests run on Linux. Of the adapters in an archive, three are started by the release checks and the rest by none. No check reaches a platform account.
- The engine image is not published. CI builds it from every commit and never pushes it.
Review
#168, #170, #171, #172, #173, #174, #177 and #180 each went through the gateway's cross-vendor review regime. Every record and disposition is on the pull requests.
The frozen corpus and SPEC.md are unchanged since v0.4.0: 30 canon vectors and 41 store vectors.
gateway v0.5.0-rc.2
A release candidate, the second made by the release workflow. It carries what v0.5.0 is to carry, and is published to try the workflow on it. Use v0.4.0 unless you are here to try the archives or the search source.
Since v0.5.0-rc.1
Named web search connections (#180, ADR-0009)
A new source, web-search, read by adapter-sources, and a provider of the same name in gateway-connections. A connection is to Tavily or to Google Cloud Search grounding. A search gives links to read through web, not documents.
- Up to six named connections, each with a daily request budget that is reserved before the network is reached. Failed calls and connection tests count.
- Endpoints are fixed in the adapter. A caller supplies none.
- A connection is checked before a request and after its answer. An answer that arrives after the connection changed, or was blocked, is refused.
- A Google answer is a generated answer with links. The answer, the links, the queries and Google's attribution markup are kept apart, and an answer without links and attribution is refused. The markup is Google's: a consumer treats it as markup it did not write.
- The acquisition is under the existing HTTP receipt shape. Its statement names the request's parameters and is not the bytes sent.
- Catalog v3 advertises the provider under a second protocol,
web-search-v1, and the local source plan names the source. A host that knows onlyconnection-v1lists the provider as unsupported and calls nothing. - The adapters module takes a new dependency,
golang.org/x/oauth2, for a service account's token.THIRD_PARTY_NOTICESnames it.
No provider was called with an account. Every test answers from a local server or a stand-in. docs/web-search.md is the contract, and says what was tested.
adapter-render writes a PDF (#174)
With --renderer PROGRAM, a request for a PDF yields a record that holds the PDF the program wrote. The program is handed the Word file the adapter made of the same content, and answers with the PDF. The adapter checks that the answer begins and ends as a PDF does; it does not open it. Without a program a PDF is refused as renderer-not-configured. No archive carries a rendering program: an operator who wants PDFs installs one, and the fonts it needs.
docs/design/rendering.md is the contract. The record of a Word file is what it was.
A source's time bound, as the code has it (#177)
Four places gave a figure for how long a source may run. None said whose figure it was, and SECURITY.md gave a ceiling the gateway does not have. Each now says both figures and whose each is. No behaviour changes.
To verify a download
sha256sum --check --ignore-missing checksums.txt
gh attestation verify <archive> \
--repo Judgment-Pack/judgment-pack-gateway \
--signer-workflow Judgment-Pack/judgment-pack-gateway/.github/workflows/release.yml \
--source-ref refs/tags/v0.5.0-rc.2What was checked before this release was published:
| Check | Where |
|---|---|
| Everything CI asks of a commit, at the tagged commit | Linux, macOS, Windows |
| Every archive read: its files are the commit's, byte for byte; each program is the bytes the packer built, from the package of its name, for the archive's platform | all six archives |
The archive run: gateway version, and gateway conform on the corpus it carries |
Linux amd64 and arm64, macOS arm64, Windows amd64 |
| Three adapters started | Linux amd64 and arm64, macOS arm64 |
docs/releasing.md says how a release is made and what each check does not establish.
What this release does not establish
- That a live Tavily or Google Cloud account is accepted, or what a live answer holds. The form of Google's source links, the size of its attribution markup and the models that support grounding are as its documentation states them, not as observed.
- That a rendering program makes a good PDF. The adapter vouches for the Word file it wrote, and for nothing of the step after.
- The
darwin/amd64andwindows/arm64archives are built and read, and run by nothing. - The adapters' tests run on Linux. Of the adapters in an archive, three are started by the release checks and the rest by none. No check reaches a platform account.
- The engine image is not published. CI builds it from every commit and never pushes it.
Review
#174, #177 and #180 each went through the gateway's cross-vendor review regime. Every record and disposition is on the pull requests.
The frozen corpus and SPEC.md are unchanged since v0.4.0: 30 canon vectors and 41 store vectors.
gateway v0.5.0-rc.1
A release candidate, and the first release of this repository made by its release workflow. It is published to try that workflow from a tag to a published release. Use v0.4.0 unless you are here to try the archives.
A release now carries the programs (#173, ADR-0008)
Releases up to v0.4.0 were a tag and notes. From this one, a release carries six archives, for Linux, macOS and Windows on amd64 and arm64. Each holds gateway, every program under adapters/cmd, SPEC.md, the corpus, the catalog and the licences.
To verify a download:
sha256sum --check --ignore-missing checksums.txt
gh attestation verify <archive> \
--repo Judgment-Pack/judgment-pack-gateway \
--signer-workflow Judgment-Pack/judgment-pack-gateway/.github/workflows/release.yml \
--source-ref refs/tags/v0.5.0-rc.1gateway version prints the release a program was built for, and the MCP server reports the same as serverInfo.version. A build from a checkout still says unversioned build. The adapters are not stamped.
What was checked before this release was published:
| Check | Where |
|---|---|
| Everything CI asks of a commit, at the tagged commit | Linux, macOS, Windows |
| Every archive read: its files are the commit's, byte for byte; each program is the bytes the packer built, from the package of its name, for the archive's platform | all six archives |
The archive run: gateway version, and gateway conform on the corpus it carries |
Linux amd64 and arm64, macOS arm64, Windows amd64 |
| Three adapters started | Linux amd64 and arm64, macOS arm64 |
docs/releasing.md says how a release is made and what each check does not establish.
Since v0.4.0
adapter-render writes a Word file (#170, under ADR-0006, #168)
A new adapter, a bare source under the command shape. It reads a format, a title and content as a closed structure of blocks, writes a Word file, and writes a version 1 render record that holds the file with its size and digest, so that a receipt's output commitment covers the file.
- The same content gives the same bytes from the same build.
- A PDF is refused by name. No rendering program can be configured in this release.
- Nothing names the adapter yet: no engine configuration, image or desk plan. An operator adds the source.
- Microsoft Word was not available to open the file with. pandoc, LibreOffice and python-docx read it.
docs/design/rendering.md is the contract.
The run of an operator's program has one home (#171)
The code that runs the OCR program moved to a package of its own, so that a second adapter can run its program from the same code. The document adapter behaves as it did, with one stated difference: page numbers are made into arguments before the run, where they were made after the deadline's check. docs/design/attachments.md now says of the two-second wait what the code does.
Decided, and not built (ADR-0007, #172)
How an engine started from its configuration is to serve the adapters it ships, as services named in that configuration. Nothing in this release implements it.
What this release does not establish
- The
darwin/amd64andwindows/arm64archives are built and read, and run by nothing. - The adapters' tests run on Linux. Of the adapters in an archive, three are started by the release checks and the rest by none. No check reaches a platform account.
- The engine image is not published. CI builds it from every commit and never pushes it.
- This is the first run of the release workflow. A fault it shows is fixed in a later candidate.
Review
#168, #170, #171, #172 and #173 each went through the gateway's cross-vendor review regime. Every record and disposition is on the pull requests.
The frozen corpus and SPEC.md are unchanged since v0.4.0: 30 canon vectors and 41 store vectors.
gateway v0.4.0
A minor release of the attested-input gateway: three changes since v0.3.1. gateway-connections gains personal file management for Google Drive, Amazon S3 and local Obsidian vaults, as a control surface apart from the engine. An operator may give a source a timeout of up to seven days. The document adapter's page walk reads its deadline in one more place.
Personal storage file management (#166)
gateway-connections can now browse a connected store and make file changes a person has reviewed, for Google Drive, Amazon S3 and an existing local Obsidian vault. Catalog version 3 advertises five operations for those three providers: files-list, files-read, files-prepare, files-commit and files-status. The earlier catalog, the attachment operations, the signed acquisition formats and SPEC.md are unchanged.
This is not an engine surface. ADR-0005 places it beside the connection controls, apart from /acquire and /act. It issues no evidence receipt and no action receipt, and it keeps no audit log: one pending or recent plan is retained per connection, for recovery only. An engine-governed write still goes through /act, and the README now says so in those words. A host must not expose files-commit as an assistant tool or as a scheduled job's action.
How a change is made:
files-preparefreezes the target, the content, the base revision and the connection generation into a plan, and changes no file. A plan expires five minutes after it is prepared.- The host shows the plan for review. A deletion also needs the exact filename, or the full S3 key, given back as confirmation.
files-commitrecords its claim durably before it sends a change, and never sends one twice. No provider request is retried. A transport failure or an unexpected provider response is reported asneeds-attention: inspect the source before starting another change.
What a change does, by provider:
| Provider | Create | Update | Delete |
|---|---|---|---|
| Amazon S3 | If-None-Match: * |
If-Match on the reviewed ETag |
If-Match on the reviewed ETag. No version ID is supplied, so deletion in an unversioned bucket can be permanent. |
| Google Drive | under an ID reserved at preparation | If-Match on a strong ETag; refused as conditional-write-unavailable where Drive returns none |
sets trashed=true; never a permanent deletion |
| Local vault | exclusive | rechecks the content digest and keeps the previous bytes under .jpack-history/ |
moves the file under .jpack-trash/ |
Bounds: a listing returns at most 24 entries, and a file read or upload is at most 4 MiB. A disconnect or reconfiguration invalidates every selection and plan made before it.
Permissions do not change by upgrading. The Drive scope remains drive.file, so only files already authorized through it are visible. S3 changes need s3:PutObject or s3:DeleteObject granted separately on the selected prefix; the gateway does not change IAM.
What this does not establish:
- The confirmation is a consent mechanism in a trusted host, not cryptographic proof that a person intended the change. Programs running as the same OS user are inside the trust boundary.
- A local recheck cannot rule out a race with another editor of the same vault.
- The tests use temporary vaults and TLS stand-ins for the providers. No change has been made against a live Google or AWS account.
docs/design/storage-files.md states the protocol, the discovery budgets and the failure handling.
Source timeouts up to seven days (#162)
--source-timeout NAME=SECONDS now accepts up to 604800 seconds, seven days, where the ceiling was 600. The default stays thirty seconds, and a source given no timeout of its own behaves as before. Each adapter keeps its own limit: set it below the gateway's timeout, with time left for cleanup and reporting.
The gateway still retains nothing between calls. A caller that must wait through a long read keeps the wait, and the response, in its own process. The gateway stores no request it could replay and no commitment salt. docs/design/durable-operations.md states that boundary and what an interruption leaves uncertain.
The page walk reads its deadline as it passes over kids (#165, closing #161)
A page-tree node may name, among its kids, a node the walk already stands under, and the walk passes over each such kid. It read no deadline as it did. A node that named itself a million times was gone through with none read, and a deadline that passed there was recorded as pdf-malformed instead of timeout. The walk now reads the deadline every 4,096 kids it passes over, and docs/design/attachments.md step 4 says so.
#161 listed fourteen other places, in decoding and decryption, that observe the deadline late and record it all the same. They are accepted as they are, for the reasons given on the issue: every adapter that parses a document is a process the gateway ends at its source timeout, and the attachments note already says an operation between two checks runs to its end.
Review
#165 went through the gateway's cross-vendor review regime, in one round. #162 and #166 were each reviewed by a model of the drafting vendor's own, in a separate context, under an explicit maintainer exception recorded on the pull request. Neither is represented as a different-vendor review. The review of #162 rejected its first candidate, which was replaced. The review of #166 requested changes, which were made and rechecked before the merge. Every record and disposition is on the pull requests.
The frozen corpus is unchanged: 30 canon vectors and 41 store vectors, and gateway conform reports 0 disagreements on the tagged source.
gateway v0.3.1
A point release of the attested-input gateway: three changes since v0.3.0. The document adapter now reads its deadline throughout opening and reconstructing a PDF. The version 1 attachment record admits a PDF the deadline stopped opening, and its encryption fields say what the reader established. The web adapter can discover a site's other pages.
The document adapter reads its deadline wherever it works
The adapter's deadline (25 seconds by default, --timeout) is meant to end a reading with an honest partial record — the pages completed and a timeout — rather than let the gateway's source timeout kill it with no record at all. Before this release, three parts of opening a PDF could run for as long as the file made them without reading that deadline. Each now reads it at a stated cadence, and the README's table states each figure:
- The scan that rebuilds a missing cross-reference (#158, closing #155). It matched object headers with one regexp pass over the whole file before its first deadline read. It now reads the deadline before it begins and between parts of 64 KiB, with every byte it inspects charged, so at most 65,538 inspections lie between two reads. It finds exactly the headers the regexp found, as a differential test and a fuzz target hold, and it is faster: about 6–8 ms on a 60,000-object file where the regexp took 94 ms. An expired deadline now costs no scanning at all.
- One object's parse (#160, closing #157). A document's lexer reads the deadline every 16 KiB it advances over, inside whitespace, comments and strings as well as between tokens: at most 20,480 bytes between two reads.
- Reconstruction's other loops (#160, closing #159). The trailer search, the index of stream ends, the key sort, the copy of a trailer's members and the object-stream header now read the deadline every 64 KiB searched or every 4,096 entries. The worst gaps measured before were about a second on a 1 GiB file; after, a few milliseconds.
A deadline read as passed now stops the document for good. Nothing read after it is cached or published, and the record says timeout. Where a deadline and another failure are both met, the one met first in reading order is reported.
The cost on ordinary files is small but measurable: extraction is 1–2% slower on real PDFs, measured pinned and in shuffled order against a control. The deadline cadence is per-token work.
A change to the version 1 attachment record (#160)
A document not opened is now exactly one of two things: reported pdf-encrypted, or stopped by the deadline while it was opened, before its encryption was established, with the timeout as its one error and no page counted. Before, attachment.Check, the reference checker of the record, refused the second shape. The gateway's routes that check records — Drive, Gmail, web, resource and connected-source — therefore turned a timed-out encrypted PDF into processing-failed. pdf-encrypted keeps its meaning: a password is required, or the handler or revision is not one the adapter implements.
The encryption fields state what the reader established. A failure of the encryption dictionary met before the deadline stands as pdf-encrypted. A reading that opened the document before the deadline records opened: true. A declaration the deadline left unread is null for that reason. If a rebuild of the cross-reference was stopped before completing its own reading, the record describes the dictionary as last read in full. docs/design/attachments.md states these rules at the encryption row and step 4. testdata/attachments/examples/failed-timeout-encrypted.json is an example of the new shape. Consumers that apply the old rule should admit it.
Website discovery (#156)
adapter-web --discover, advertised as web-discovery in the source catalog and the local plan, returns a signed navigation manifest of a public HTTPS site's other pages. The selected pages then go through ordinary web acquisitions, each with its own receipt. Discovery stays on the exact origin and checks robots.txt and every redirect. It caps pages, depth, links, bytes, requests and elapsed time. It takes no credentials and renders no JavaScript.
Review
#158 and #160 went through the gateway's cross-vendor review regime. #158 had two rounds; #160 had five, plus two same-vendor verification workflows. Every round and its disposition are recorded on the pull requests. Gaps of the same kind in decoding, decryption and the page walk's cycle shortcut, which predate this release, are filed as #161.
The frozen corpus is unchanged: 30 canon vectors and 41 store vectors, and gateway conform reports 0 disagreements on the tagged source.
gateway v0.3.0
Third release of the attested-input gateway: 64 commits since v0.2.0 that turn a service whose only source was a hand-written script into an engine. The receipt has a version 3; the adapters module beside the standard-library gateway holds the sources; a fifth process speaks MCP; an engine image carries all of it; two workflow-tool plugins and a second, TypeScript implementation of the verifier answer to the same frozen corpus; documents are read into signed attachment records; and gateway-owned connections reach Google Drive, Gmail, Notion, Obsidian, public HTTPS pages and Amazon S3. Eight of the pull requests are from two external contributors.
The receipt, version 3
SPEC.md §1.2a (#101) specifies the version 3 receipt: an acquisition record, commitments over the arguments under a fresh salt that is returned to the caller and never retained, the identity of the caller the engine proved, and action receipts. What a receipt signed before the change means afterwards is exactly what it meant before: a version 3 verifier verifies a version 2 store unchanged, the seal is the same record under both versions, and a verifier that knows only version 2 refuses a version 3 receipt. verify reads the version 3 vectors (#102); serve mints version 3 by default and version 2 on request (#103). Adapter sources report their acquisition in the result envelope (#104, ADR-0002); a decision record's own citations are resolved from the record's side (#112) and the golden record is checked both ways, history and live facts agreeing on the postgres platform (#116). Seals hold across a restart: /acquire consults the registry for a session it does not hold (#122). A validly signed seal counting below zero is a seal (#137).
One engine, four processes — then five
ADR-0001 (#97) adds the adapters/ module beside the gateway and the boundary it lives under. serve starts a source with a declared environment, an optional distinct user and a bounded output, and refuses a readable seed (#100); serve --config names the platforms an engine serves and refuses what the isolation claim does not survive (#107); connect writes a platform entry only after the platform answered (#108, #109). identity decides who may call, from a key set the operator holds and reads once at start, and the receipt names the caller it proved (#110). A write goes through the engine as an action, refused unless its judgment is there (#114). Three adapters: adapter-airbyte, one page of one stream from a pinned connector image (#105); adapter-mcp, one tool call on a vendor's MCP server over stdio (#106); adapter-http, one request over TLS to an endpoint the operator fixed (#117). The engine image (#111, #113, #115) builds both modules, the catalog and the corpus on a distroless static base with no shell and no libc, pinned by digest, with the runtime carried at its release.
ADR-0003 (#120, #121) adds the fifth process: gateway mcp, a client of the signer's HTTP surface and nothing more, so an MCP client calls a platform's live tools through the engine and the receipt rides with the answer. Tool descriptors are captured at connect, pinned, and served verified from the MCP server (#124, #126–#128).
/acquire bodies are bounded by --max-request and each source by --source-timeout (#135), and /acquire, /act and /seal read their envelope by exact member names, given once: {"session":"sealme","SESSION":"keepme"} no longer seals keepme (#147).
Plugins, and a second implementation
An n8n node and an Activepieces piece reach the engine from workflow tools (#118), each run the way its ecosystem runs it against a live engine (#119) and held to its refusals against a stand-in (#123); the n8n node is published from GitHub Actions (#130). verify-ts/ (#129) is a second implementation of the attestation format — canonical form and registry-anchored verification of receipt versions 2 and 3 — answering to the frozen corpus, with a CI job that checks both implementations agree.
Documents
ADR-0004 (#133) decides that documents are an adapter under the command shape, writing a version 1 attachment record. adapter-document (#134) reads an attached text file, normalized, or a PDF, for page text, with OCR delegated to an operator-supplied executable when asked. #134 landed with its last fixes reviewed by a model of the drafting vendor's own, under a one-time exception, with a different-vendor follow-up owed; that follow-up ran over #134 and #135 together and reproduced 24 defects, every blocker and major reproduced a second time by the maintainer before it was accepted. They are fixed in #145 (the record reads what the page shows), #146 (a bound the reader states is a bound it holds), #147 (the envelope above), and #150 (six further review rounds over #145's area: object-stream headers read no further than a bound, encodings established by ranges of one length, and a scan the reader could not finish leaving no reading publishable). #146's seventh round, run after its merge, found one bound still not held — an array charged less than the room append grows it to, so a small file held 66.8 MiB of operand against the stated 64 — fixed in #152, where an array is charged the capacity it grows to, before it grows, including the moment the old and new backing arrays are both held. The same round's findings on the request read are fixed in #153: an exhausted arbitration refuses the request, and the wait for an on-time result is tested as the adapter's own receive. #154 makes the document adapter's race-detector run green: a data race between tests, wall-clock allowances and test deadlines scaled under the detector, and the deadline-cut opening measured against the one pass over the file it cannot interrupt. That last pass is issue #155.
Connections
gateway-connections owns app registration, consent, tokens, refresh and revocation, and hands the adapters single-use grants. Google Drive files selected through Google's own Picker (#139); read-only Gmail message exports, with no sending or mailbox mutation (#140); publisher Google OAuth registration in local bundles (#141), public distributions being unregistered (#142). Notion pages through bounded hosted MCP OAuth, and Obsidian notes under a confined vault root (#143). gateway-connections --catalog lists what a companion implements without opening account state (#144), and catalog v3 describes connection UI and source protocols so a host can use a new provider without a release of its own (#149). adapter-web retains a bounded snapshot of one explicitly selected public HTTPS page, text file or PDF, validating the public address on every DNS answer and redirect (#148). Amazon S3 files from one bucket and prefix, under explicit credentials and the official SigV4 signer, four selections of 4 MiB each; live AWS acceptance remains pending (#151).
Hardening and tests from contributors
Verification refuses a store root that is not a directory (#79) and a registry path that cannot be read (#84), and the spec states the verdict for an absent store root (#92). Contributors pinned argumentsDigest's keyed commitment (#76) and argumentsKey's derivation against a byte-literal digest (#94), that gateway conform exits non-zero on disagreements (#96), the method contract of /acquire and /seal (#85), that /acquire refuses non-canonical arguments before the source runs (#86), and that every loadSeals drop row has exactly one obstacle (#80). A test binary committed by mistake is removed and ignored (#136), and a bound test is allowed what the connection buffers (#125).
Documentation
Five decision records (ADR-0000 to ADR-0004) and eighteen design notes under docs/design/, from the receipt to each connection.
The frozen corpus grew with version 3: 30 canon vectors, 21 store vectors for version 2 and 20 for version 3, and gateway conform reports 0 disagreements on the tagged source.
gateway v0.2.0
Second release of the attested-input gateway: 29 commits of hardening, one verifier fix that changed what a verdict means on Windows, and the first external-contributor wave — twelve merged pull requests from five contributors, every one verified and mutation-tested before landing.
The verifier fix
On Windows, os.ReadDir on a regular file reports ERROR_PATH_NOT_FOUND, which os.IsNotExist treats as absence — so a store whose receipts path existed but was unreadable verified clean on that platform only. Found by a contributor's boundary test (#63), proved platform-split, and fixed (#71): absence is now decided by os.Stat, present-but-not-a-directory is a hard refusal, and ReadDir errors propagate unconditionally. SPEC.md §4.1's table now enumerates all three failure shapes explicitly — absent, present-but-not-a-directory, and a directory that cannot be read (#71, #75) — so a clean-room implementation cannot be steered into the removed behavior. Permission-fixture tests pin both error legs.
Hardening since v0.1.0
/acquireand/seal: request bodies bounded (#44), admission race-safe (#43), trailing JSON request values rejected (#37).- Verification follows §1.4's first-failure order exactly (#42).
gateway keygenrefuses to replace an existing path (#41);gateway serverejects duplicate and malformed--port(#39), duplicate source names (#31), malformed options before startup (#23), and source commands that do not resolve (#50).
The test wave
External contributors pinned, among others: keyIDFor's truncation against an independently computed digest (#51), the canon subcommand's byte-exact contract (#52), the receipt store's append-only refusal (#58), §4.1's graded verdicts for a missing receipts root (#59), the corpus README's vector counts (#60), readPublicKey's accepted and refused encodings (#61), JSON-only session counting (#70), and GET /registry as a byte-faithful anchor (#73). Several of these are the only guard in the tree for the property they hold — verified by mutation, not assumed.
Documentation
Runnable quickstart (#27) and a trust-boundary diagram (#29).
The frozen corpus is unchanged: 30 canon vectors, 19 store vectors, and gateway conform reports 0 disagreements on the tagged source.
gateway v0.1.0
First binary release of the attested-input gateway, built from the tagged source (7b3afab).
What this is
One Go binary, standard library only: gateway canon | verify | conform | serve | keygen. Receipt format version 2 — Ed25519 signatures with a prevSignature chain, keyId on every receipt, signed seals, and /publickey — with SPEC.md normative for the format and the frozen conformance corpus (30 canon + 19 store vectors) as its teeth. The gateway binds localhost and invokes subprocesses by design, which is why it is deliberately a separate artifact from the judgment-pack runtime and is never folded into it.
Why a published artifact
Downstream consumers stage binaries through a verified lock — name, version, digest, checked before anything executes. Until now the only way to pin this gateway was an untagged source build. This release gives the pin a published, immutable target, per the replay discipline documented in judgment-pack-runtime#94: record the artifact digest next to what it produced.
Verification
sha256sum -c checksums.txt --ignore-missingagainst your downloaded archive.- The published
linux_amd64binary was run against the corpus at this tag before publication:gateway conform→ 30 canon vectors, 19 store vectors, 0 disagreements. The other platforms are cross-compiled from the same source and were not corpus-verified on their native platforms. - Build:
go1.26.5,CGO_ENABLED=0 go build -trimpath -buildvcs=false -ldflags "-s -w -buildid=", archives normalized (sorted entries, zeroed ownership, fixed mtime).
Contents
Each archive carries the binary plus LICENSE, README.md, and SPEC.md.
Two standing bounds from SPEC.md worth repeating with any distribution: the gateway's public key must reach verifiers out of band (fetching it from the audited gateway proves consistency, not authenticity), and the corpus is frozen — a vector change is a spec change.