Skip to content

What each deployed surface carries


rank: decision outranks: [] doc_id: PTV-DEC-0023

Section titled “rank: decision outranks: [] doc_id: PTV-DEC-0023”

Date: 2026-08-25 Status: open Supersedes: none Superseded-by: none — current Prompted by: PTV-FND-0062 defect 2 Terminal state of this record: the two surfaces declared as they are, both standing. It changes no build script’s behaviour and copies no new path.

This is the most useful fact in this record and the one a future reader will otherwise supply for themselves.

Dockerfile:43 stages docs/decisions alone. scripts/vercel-build.sh:18 stages the whole docs/ tree. Neither references the other, and no record before this one states that they differ.

They were authored independently, a day apart, by unrelated tasks:

linearrived indate
COPY docs/decisions77d378f3 — Task 17, petrova.host v0 on Railway2026-05-09
cp -a docsea745cb6 — moved out of vercel.json’s buildCommand for a 256-character limit; the copy itself predates the script2026-05-10

There is no policy to converge to. A reader who finds two conventions will assume intent and try to preserve it. There was no intent. There were two tasks.

They are not two policies. One is a policy and one is an absence.

Section titled “They are not two policies. One is a policy and one is an absence.”

The Dockerfile enumerates and justifies each path in a comment beside it: spec and schemas because otherwise “the server crashes at boot”, contracts because it is “read at boot for the freshness log”. Every path earns its place and says so.

vercel-build.sh copies the tree and says nothing. That is not a competing policy; it is an unstated one. Declaring the divergence is what makes the absence visible, and closing it is the cheap half of this record.

Railway — Dockerfile. Enumerated, each path justified by a demonstrated runtime need. docs/decisions is there because host/src/sources/petrova.ts:90 joins it, and that is the only disk read of docs/ anywhere in host/src.

docs/findings is deliberately absent and its absence is correct: the host reads findings over the GitHub API, not from disk — host/src/sources/audit.ts:3,88, App-authenticated Octokit. A finding that is not in the image is still reachable to the surface that wants it.

Vercel — scripts/vercel-build.sh. Takes the tree. The grounded reason, measured rather than assumed: the function bundle also embeds cli/dist (vercel-build.sh:25), and the CLI carries disk readers for more of docs/ than the host does — docs/findings at cli/src/validate.ts:183 and cli/src/repo-walker.ts:49, docs/decisions at cli/src/verbs/declare_baseline.ts:71 and cli/src/cairnet/fleet/rotation-gate.ts:22.

Not confirmed: whether any Vercel request path actually exercises those CLI readers. The bundle contains code that could read them; that is not the same as a route that does. This record states the reachable surface, not an exercised one, and marks which is which.

Note that Railway also carries cli/dist (Dockerfile:29) without docs/findings. Any code path on that image reaching the CLI’s findings readers would find an empty directory rather than an error. No such path is known; it is recorded as a latent asymmetry rather than a defect, because nothing measured shows it being reached.

The two surfaces stay as they are.

Convergence would mean inventing a policy under time pressure to satisfy G-P3-6, whose wording PTV-FND-0062 records as defective on exactly this point — the gate does not say which console it means. Building the reconciliation before the thing it reconciles is decided is the same error as writing a requirements matrix before the assertions exist.

It also carries a cost that should not be absorbed silently: docs/ is 400+ files, and growing the Railway image to satisfy a clause that may not survive the close doc’s rewording would leave the image grown for nothing. Images do not shrink back on their own.

  1. The P3 close reworks G-P3-6’s “reachable” clause and names the surface it means, alongside the G-P3-8 and G-P3-10 unevaluability already listed.
  2. If that rewording concludes both surfaces are required, convergence becomes a decided change with a stated reason — and this declaration is its prerequisite, because it is the first record of what each surface holds.
  3. Only then does any new path get added to either script.

Adding docs/evidence/ to the Dockerfile now would produce a third convention rather than resolving the first two.

What this permits in the meantime: design for two, build for one

Section titled “What this permits in the meantime: design for two, build for one”

A consumer that needs to read an evidence artefact from disk is not blocked by the ordering above. It is built now against the surface that already carries the path, and named for the surface that does not:

  • The host source is designed for two surfaces — the path it reads is a parameter of the source, not a constant compiled into it, so adding Railway later is a registration and not a rewrite.
  • It is built for one: Vercel, which stages the whole tree today and so already reaches docs/evidence/ with no change to either build script.
  • The Railway source is a named follow-on, gated on step 1 above — the P3 close naming the surface G-P3-6 means. It is not deferred indefinitely and it is not silently dropped; it is blocked on a decision with an owner.

This is what “no new path is added to either script” already implies, written down because it was ruled in prose twice and did not survive to the next turn either time. A ruling that lives only in a conversation is re-litigated by the next reader of the artefacts, who has no access to the conversation.

  • It does not bless the tree-wholesale copy as correct. It records it as unstated-until-now and now stated.
  • It does not rule that the surfaces must eventually match.
  • It does not close PTV-FND-0062. Defects 2 and 3 there are gate-wording problems and this record is a prerequisite for fixing them, not the fix.
  • docs/findings/20260825-1900-g-p3-6-names-the-wrong-gate-and-cannot-be-read-as-written.md — PTV-FND-0062, defect 2.
  • Dockerfile:29,41-51, scripts/vercel-build.sh:16-26 — what each surface stages.
  • 77d378f3, ea745cb6 — the independent origins.
  • host/src/sources/petrova.ts:90 — the only disk read of docs/ in the host.
  • host/src/sources/audit.ts:3,88 — findings read over Octokit, not disk.
  • CLAUDE.md — both surfaces serve a build-time snapshot.
  • Subagent: PTV-SCF-0001 P3 (session 2026-08-25)
  • Human: ☑ (proxy) countersign — that the two surfaces are declared as they stand rather than converged, that the divergence is recorded as never having been decided, and that no new path is added to either script until the P3 close names the surface G-P3-6 means. Countersigned by human:devarno on 2026-08-25, by directive in session; ticked by the agent as scribe, not as signatory.