Disclosure first: this is not a pre-registration
rank: decision outranks: [] doc_id: PTV-DEC-0019 title: N8N-27 exit condition — what closes the store sweep, and what it knowingly leaves unswept date: 2026-08-17 status: closed owner: petrova-codes scaffold: PTV-SCF-0001 phase: P4 supersedes: none depends_on: docs/decisions/2026-08-17-what-counts-as-a-credential-store.md
Section titled “rank: decision outranks: [] doc_id: PTV-DEC-0019 title: N8N-27 exit condition — what closes the store sweep, and what it knowingly leaves unswept date: 2026-08-17 status: closed owner: petrova-codes scaffold: PTV-SCF-0001 phase: P4 supersedes: none depends_on: docs/decisions/2026-08-17-what-counts-as-a-credential-store.md”Disclosure first: this is not a pre-registration
Section titled “Disclosure first: this is not a pre-registration”PTV-DEC-0018 was written before the sweep, deliberately, so the store boundary
could not be settled while reading results. This document was not. The
corrected multi-source pass finished at 13:56 and this was written afterwards, so
the single most corruptible operation — grading a result against a definition
written after seeing it — is available here and must be blocked explicitly rather
than assumed away.
How it is blocked: every clause below is traceable to PTV-DEC-0018
§“What the sweep must record”, which was pre-registered — the repo denominator
with itemised skips, per-store class and reachability, multi-source resolutions,
and what the instrument cannot see. Nothing here is a criterion invented to fit
hits-org-ms.tsv. Where this document adds a requirement, it comes from
PTV-FND-0042 (per-class positive control), which is a method rule and not a
result.
The reader should still treat the ordering as a defect in the record. It is recorded rather than repaired because repairing it is not possible after the fact.
What counts as a store
Section titled “What counts as a store”By reference to PTV-DEC-0018 §“The definition” and its in-scope/out-of-scope
tables. Not widened here. A boundary change requires a superseding decision
doc (MR-7), not a clause in the exit condition of the sweep it governs.
The denominator, as measured
Section titled “The denominator, as measured”scanned-org-ms.tsv 465 rows one row per repo attempted ok 417 empty 48 default branch has no files at depth 1 clone-fail 0hits-org-ms.tsv 10 rows multi-source class, corrected patternrepos with hits 2 rocky-hq/console, grace-hq/rockyThe earlier all-seven-class pass over the same 465 (scanned-org.tsv) recorded
ok=416, empty=48 (identical set, verified by diff), clone-fail=1
(v01t-io/integration-hub).
The 465 is a contested population and stays contested
Section titled “The 465 is a contested population and stays contested”PTV-DEC-0018 §“The denominator is already unstable” records two enumerations
that disagree: 30 orgs / 465 repos (PTV-FND-0032) against 40 orgs / 458
in-org / 524 accessible. 465 is the PTV-FND-0032 population, reused here so
the two figures are comparable, and the reconciliation is still unmeasured.
Any coverage figure in this sweep is therefore a fraction of a number that has
not been reconciled, and must be read that way. Reconciling it is part of
N8N-27; it is not waved through by this document.
The 48 empties, itemised
Section titled “The 48 empties, itemised”Not summarised — PTV-DEC-0018 requires skips itemised and reasoned, because
the store-denominator error came from three known stores with no record of how
“known” was established.
choco-hq(42):black-ice,choco-analytics,choco-assistant,choco-auth,choco-billing,choco-cli,choco-compiler,choco-edge-gateway,choco-forge,choco-gateway,choco-gitops,choco-infra,choco-ledger,choco-mcp-server,choco-observability,choco-pipes,choco-sdk-go,choco-sdk-python,choco-sdk-ts,choco-search,choco-sync,choco-ui-kit,choco-vault,choco-verifier,choco-web,choco-webhooks,echo-chamber,fork-node,frontend-template,golden-press,library-template,null-route,service-template,the-boiler-room,the-cocoa-bean,the-compiler,the-ledger,the-recipe-book,the-river,the-vault,vest-node,zero-point- other (6):
clari-tools/web,Dev4rno/featr.io-server,rocky-hq/algo,v01t-io/ci-cd-pipelines,v01t-io/helm-charts,v01t-io/kubernetes-manifests - clone-fail (1, first pass only):
v01t-io/integration-hub
Reason, uniform: git clone --depth 1 of the default branch produced a tree with
no files outside .git. That is consistent with an unpushed placeholder repo,
which is what 42 of 48 being choco-hq scaffolding suggests — but the sweep
measured emptiness at depth 1 on one branch, not emptiness of the repository.
Two of them are named choco-vault and the-vault. Nothing about the name
is evidence, and nothing about the sweep clears them either. They are unswept
repositories whose names are in the class being hunted, and that is exactly the
combination this document refuses to round to zero.
Knowingly unswept residual
Section titled “Knowingly unswept residual”Stated as limits, per PTV-DEC-0018 §4 — a limit, not a clean negative.
| Residual | Why the instrument cannot see it |
|---|---|
| Non-GitHub code | The population is gh-enumerated; anything not in an accessible org or user account is outside it |
| Private gists | Never enumerated by any pass |
| Non-default branches | --depth 1 on the default branch only; a store on a feature branch is invisible |
| The 48 empties | Above. Includes two vault-named repos |
| Vendored dependencies | --exclude-dir=node_modules,vendor,dist,.next,build,.venv — a store inside a dependency is excluded by construction |
| Excluded test trees | --exclude-dir=tests,test,e2e,fixtures,__tests__ and the noise pattern. PTV-FND-0041 removed real test-fixture noise this way; the cost is that a store in a test tree is now unseeable |
| Local worktrees absent from the org list | Measured instance: v01t-io/meta, which holds the vendored rocky-hq source behind the /migration/state/ noise, is not in org-repos.txt — the org has meta-* repos, no bare meta. The local set is not a subset of the org set, in either direction |
| Credentials written into a database through a UI | Reading code finds stores declared in code (PTV-DEC-0018 §4) |
| A store fetched from a service whose name is itself a secret | Same clause |
| GitHub Actions secret values | Structurally unsweepable — write-only by design (PTV-FND-0033 corollary). Names enumerate across 465 repos; no value read path exists for anyone |
Vercel sensitive variable names | sensitive_names.py died on its first call with HTTP Error 403, output contains zero SENSITIVE lines. ~63 project-level declarations exist per sweep_vercel2.py’s incidental count. Unmeasured, not empty (PTV-FND-0042) |
Per-class control status
Section titled “Per-class control status”From n8n27/control-filter.sh (PTV-FND-0042). A class with no known-true input
anywhere in the estate cannot be validated, and its zero is not a measured zero.
| Class | Control | Status |
|---|---|---|
multi-source | rocky-hq/console:src/lib/n8n-client.ts:10 + 3 siblings | controlled, corrected pattern, re-run complete |
app-vault | src/lib/vault/store.ts, crypto.ts, src/app/api/vault/route.ts | controlled, retained retrospectively in hits-org.tsv |
db-credential | choco-hq/choco-hq:infrastructure/migrations/000003_api_keys_and_sessions.up.sql:5, skyflow-blue/infrastructure:migrations/001_core_schema.sql:153 | controlled |
secret-file | none exists | UNCONTROLLED |
mounted-secret | none exists | UNCONTROLLED |
hardcoded-key | none exists | UNCONTROLLED |
runtime-fetch | none exists | UNCONTROLLED |
The four uncontrolled classes carry 123 + 29 + 10 + 1 = 163 of the 240 candidate hits in the all-seven pass. That is the majority of the sweep’s output sitting behind an unvalidated instrument, and it is the reason this document exists rather than a closure note.
The closure test
Section titled “The closure test”N8N-27 closes when all four hold:
- Denominator recorded — 465 with the 48 skips itemised and the population named, plus a stated position on the 465-vs-458-vs-524 disagreement.
- Per-class control status recorded — every class either has a passing
positive control or the label
UNCONTROLLED. Classes may close uncontrolled; they may not close silently uncontrolled. - Residual stated — the table above, as limits.
- Confirmed stores listed with reachability — per store: repo, path, class,
credential held if determinable, and whether it is reachable in a live
deployment or only in principle (
PTV-DEC-0018§2). Candidates are not promoted by count (PTV-FND-0041).
N8N-27 does not close because a scan finished, because a count is small, or
because the confirmed store list is a single entry. As measured today, 1, 2 and 3
are satisfied by this document plus PTV-FND-0042; 4 is satisfied only for the
classes that have controls.
What this unblocks, and what it does not
Section titled “What this unblocks, and what it does not”N8N-01 and N8N-03 become schedulable when the closure test passes and
this decision is countersigned — not before. The mint remains the structural
block that nothing in this item routes around: no store enumeration produces a
replacement credential.
N8N-30 (rocky-console’s vault holds GitHub and Anthropic credentials no
inventory has counted, PTV-FND-0041 §Consequences 4) stays outside this
close-out rather than being absorbed into it.
Amendment — 2026-08-17, before countersign (PTV-FND-0044)
Section titled “Amendment — 2026-08-17, before countersign (PTV-FND-0044)”Appended rather than edited in place (MR-7). The clauses above stand as
written; this records what has been measured since.
On the disclosure above, and why it is the mechanism rather than an apology.
PTV-DEC-0018 was pre-registered precisely so that a document like this one
could be written after the run without the grading being shaped by it. The
definition of a store, the requirement to itemise skips, and the requirement to
state the residual all existed before any result did; only the prose grading them
came after. That is pre-registration working as intended. A disclosure of the
ordering is what lets a reader confirm it, and it should be read as the control
holding, not as a defect being confessed.
Per-class control status — four rows superseded. secret-file,
mounted-secret, hardcoded-key and runtime-fetch are no longer
UNCONTROLLED. Synthetic controls (n8n27/control-synthetic.sh) plant one
instance of each class; all four fire. Their recall against ten realistic
in-scope variants is 4 of 10, with the six misses named individually in
PTV-FND-0044. Read every negative in these classes as 4/10 recall against ten
named variants, not as absence.
Residual — the 48 empties row is discharged. All 48 return
409 Git Repository is empty with size == 0 and no refs of any kind, so they
are empty at ref level and not merely on the default branch. choco-vault and
the-vault included; both were created and never written to (one-second
create/push signatures, and choco-vault is archived).
Residual — a new row. Pattern recall is bounded by naming convention. Six
of ten probes miss because the patterns enumerate vendors and spellings rather
than matching values: Kubernetes secretName, HashiCorp vault kv get, Azure
Key Vault, .env.vault, docker-compose secrets:, and a lower-case SQL read
of a table named integration_credentials. Value-matching is omission-resistant;
name-matching is lower-confidence by construction (PTV-FND-0044).
Withdrawn. The Vercel sensitive names are not unmeasured. A re-run
census gives PROJECTS=72 SENSITIVE_ROWS=63 ERRORS=0, matching PTV-FND-0037
exactly. PTV-FND-0042’s claim to the contrary is retracted in PTV-FND-0044;
the sensitive_names.py 403 is a real defect in that script and nothing more.
Closure test status after this amendment: clauses 1, 2 and 3 hold. Clause 4 — confirmed stores listed with reachability — remains open for every class, and is the next move.
Amendment — 2026-08-17, before countersign (PTV-FND-0052)
Section titled “Amendment — 2026-08-17, before countersign (PTV-FND-0052)”Appended, not edited (MR-7). Records the reachability pass the previous
amendment named as the next move.
Clause 4, repo layer: discharged. All 29 repos carrying candidate hits now have a measured deployment verdict, from three instruments — GitHub facts, platform project existence keyed on the git link rather than the project name, and CI deploy paths read rather than counted.
DEPLOYED 10 repo(s) 104 hit(s)UNDETERMINED 1 repo(s) 18 hit(s)UNBUILT 18 repo(s) 118 hit(s)Clause 4, store layer: still open. 118 of 240 candidates are code copies
under PTV-FND-0043 and cannot be stores. The remaining 122 have not yet been
adjudicated hit by hit into store / not a store, nor had the credential each
holds determined. Clause 4 closes on that list, not on this triage.
Residual — two rows added, both bounds on this pass.
| Residual | Why the instrument cannot see it |
|---|---|
| Deployments with no git link | 35 of 65 Railway services have source.repo == null (CLI- or image-deployed). “No platform link” is therefore not “not deployed”; smo1-io/purr-api is the measured instance and is recorded UNDETERMINED rather than resolved |
| Hosts outside Vercel, Railway and GitHub Actions | UNBUILT is negative across exactly those three. nestr-tools/perch deploys to a Kubernetes cluster none of them enumerate — a measured instance of a host outside the instrument, not a hypothetical |
A boundary question raised and deliberately not answered.
sparki-tools/mobile-ios is reachable as a client binary. The definition in
PTV-DEC-0018 says “reachable by a running deployment” and does not separate
server-side from client-side; its 26 hits ship to every install. Widening or
splitting that clause requires a superseding decision doc, so it is recorded here
as an open boundary question and the hits are counted under the definition as
written.
A guard limitation, recorded against the hardening this document relies on.
The PTV-FND-0044 guards exit non-zero on empty or traceback-only output. They
passed on a run whose homepage column was shifted by one field for 18 of 29 rows,
because the output was neither empty nor a traceback. Shape guards (arity, column
types) are now asserted alongside. Read every prior “guard ok” as the command
produced output, never as the output is correct.
Amendment — 2026-08-17, before countersign (PTV-FND-0046, PTV-DEC-0020)
Section titled “Amendment — 2026-08-17, before countersign (PTV-FND-0046, PTV-DEC-0020)”Appended, not edited (MR-7). Two verdicts in the previous amendment’s table
are corrected, and one exclusion is proposed.
Corrected verdicts. Both move toward unbuilt.
was (PTV-FND-0045) now (PTV-FND-0046)DEPLOYED 10 repo(s) 104 hit(s) 9 repo(s) 98 hit(s)UNDETERMINED 1 repo(s) 18 hit(s) 0 repo(s) 0 hit(s)UNBUILT 18 repo(s) 118 hit(s) 20 repo(s) 142 hit(s)nestr-tools/perch— DEPLOYED → UNBUILT. Every step ofdeploy.ymliscontinue-on-error: trueandKUBE_CONFIG_STAGINGdoes not exist; its greenDeploy / successrun is manufactured by the error swallowing. It has never reached a cluster.smo1-io/purr-api— UNDETERMINED → UNBUILT, on four signals that are not the name: null source, null image,FAILEDlatest deployment from 2026-03-15 with nothing since, placeholder CI.
The Kubernetes residual row is withdrawn as written. The previous amendment
recorded perch as a measured instance of a host outside the instrument. It is
not, because it is not a host at all. No repo in the candidate set is confirmed
on Kubernetes, and whether the estate runs any cluster is unanswered by every
instrument in this item. The residual row survives in weaker form: UNBUILT is
still negative across Vercel, Railway and GitHub Actions only, and other hosts
remain outside — but no measured instance of one is now claimed.
A recall bound that tightens clause 2. mounted-secret recall measured
against real in-estate input, in perch’s tree: 6 of 31 (19%), and all 6 are
the default Kubernetes service-account mount. Every mounted-secret zero in this
sweep is bounded below by 19%, not by the 4/10 synthetic figure. Clause 2’s
per-class status is unchanged in kind — the class remains controlled only
synthetically — but its number is now worse and measured.
Residual — one row added, one clarified.
| Residual | Why the instrument cannot see it |
|---|---|
| A green CI run proves nothing | continue-on-error on every step yields success from a job in which nothing executed. Any pass keying on run conclusions inherits this across 465 repos of green checkmarks |
| DNS resolution, demoted | Not evidence in either direction. devarno-cloud/casa is DEPLOYED (Vercel host-casa, git-linked) and its declared homepage casa.devarno.cloud is NXDOMAIN. DNS stays in the discharge order as corroboration and may never decide a verdict |
skyflow-blue/infrastructure is not a fifth store class. Its two Actions
secrets are inside PTV-FND-0032’s complete name-level enumeration
(readable=465 noaccess=0), and platform environment variables are excluded by
PTV-DEC-0018’s out-of-scope table. Seen, and deliberately excluded. What is new
is only that the exclusion assumed such a credential belongs to a deployed
application; here it belongs to an unbuilt repo, so nothing pairs the credential
with a consumer.
Clause 4 scope narrows, pending PTV-DEC-0020. That decision proposes that a
credential shipped to every client install is disclosed, not stored, and is
handed to a new item. If countersigned, sparki-tools/mobile-ios’s 26 hits leave
this sweep and the store candidate set becomes 72 hits across 8 repos. Until
it is countersigned the 26 remain formally in scope and clause 4 cannot close.
How clause 4 must be reported when it does close. Per surviving hit: a verdict and the class it came from; and per class, a confidence — controlled classes at their measured recall, the four synthetic-only classes flagged bounded-below. A single aggregate figure over the surviving set is prohibited: it would launder the uncontrolled classes into the controlled ones, which is the laundering the recall bound exists to prevent.
Amendment — 2026-08-18, before countersign (PTV-FND-0047)
Section titled “Amendment — 2026-08-18, before countersign (PTV-FND-0047)”Appended, not edited (MR-7). Records the CI-outcome audit that the previous
amendment’s guard defect made necessary, and which was named as a precondition
of countersigning this document.
The audit is complete. Scoped to the verdicts actually exposed — those
resting on reading a workflow body rather than on a platform’s git-link record,
which is where the read-the-verb-not-the-guard defect lives. Eight of nine
DEPLOYED verdicts rest on a platform project the platform itself reports as
linked to the repo, and are not exposed. One rested on CI body reading, and it
reversed.
sparki-tools/mobile-ios — DEPLOYED → UNBUILT. No Actions secrets at repo
scope or in either environment; six consecutive iOS Deploy failures; latest
run’s jobs Deploy to Testing → failure, Deploy to Development → skipped;
nothing since 2026-03-15. The perch defect by the opposite route: perch hid
failure behind continue-on-error, mobile-ios failed visibly and the
instrument was not looking.
Generalisation, recorded as a limit on the instrument rather than a fixed defect: a workflow file states intent; deployment is a fact about execution. All three reversals in this item graded intent as outcome.
PTV-FND-0045 PTV-FND-0046 now (PTV-FND-0047)DEPLOYED 10 / 104 9 / 98 8 / 72UNDETERMINED 1 / 18 0 / 0 0 / 0UNBUILT 18 / 118 20 / 142 21 / 168 (70%)Clause 4’s adjudication surface is 72 hits across 8 repos:
rocky-hq/console, choco-hq/choco-hq, kahn-hq/kahn,
sparki-tools/api-engine, traceo-cat/traceo-mcp-server, devarno-cloud/casa,
devarno-cloud/landing, Dev4rno/skyflow-client. Reporting form is unchanged
from the previous amendment: per-hit verdict plus originating class, per-class
confidence, no aggregate.
PTV-DEC-0020 no longer gates this document. It was blocking on 26
unadjudicable client-shipped hits; those hits are unreachable, so the hole it was
written to close does not exist. It stands as pre-registration.
Direction flag, carried forward unresolved. Three verdicts have reversed and
all three moved toward unbuilt, shrinking the surviving set each time. That is
the shape motivated reasoning takes. Each reversal rests on a positive query —
continue-on-error plus a missing secret, a FAILED deployment status, six
recorded run failures across three empty secret scopes — and none on an argument
from silence. The flag stays in the record rather than being resolved, so a
reviewer can check the direction rather than take this paragraph for the check.
Amendment — 2026-08-18, at countersign
Section titled “Amendment — 2026-08-18, at countersign”Appended, not edited (MR-7).
A guard on the surface size itself, added at countersign.
The candidate surface has moved 104 → 98 → 72 across three revisions. Every
movement was in one direction, and every one came from a defect found in the
reachability instrument. Adjudication now proceeds with a different
instrument — the seven class patterns, four of which are controlled only
synthetically and whose recall is measured at 19% against real input
(PTV-FND-0046).
These two instruments’ error rates do not compose, and the shrinking surface must not be read as convergence. It is the deployment layer becoming more accurate while the detection layer’s bound is unchanged.
Therefore: the number 72 carries no confidence claim. It is the count of candidates that survived reachability triage, not a measured total of stores, and not an upper bound on them — the detection layer’s misses were never in it to begin with. Per-class confidence with no aggregate (previous amendment) guards the store list; this clause guards the surface it is drawn from.
The durable output of this item, for a reader who has only the tables.
A workflow file states intent; deployment is a fact about execution. A CI
successis evidence about an exit code and nothing else.
Both reversal routes are instances: nestr-tools/perch hid failure behind
continue-on-error; sparki-tools/mobile-ios failed visibly and the instrument
was not looking. Opposite routes, one defect.
Countersign
Section titled “Countersign”- Human countersign — the closure test above is what
N8N-27is measured against, and the residual list is accepted as knowingly unswept
Countersigned by human:alex@devarno.com on 2026-08-18 — restated here from
this document’s own prior status: line (countersigned 2026-08-18 — alex@devarno.com), mapped to the recognized open|closed|superseded
vocabulary 2026-09-05. No fact about who signed or when is changed.
Unchecked, this decision is open and any claim that N8N-27 is closed is
provisional against it.