Glossary

Process and Attribution

How fragcap recovers which process owns a flow: the socket table, the process tree, and the join between them.

Attribution

Associating a captured packet with the process that sent or received it.

Capture happens at the network driver layer, below the socket layer, by which point the operating system has discarded the association. Recovering it means joining packets against a separately maintained record of open sockets.

Why it matters here

Attribution is fragcap's reason to exist. Packet capture is solved; attribution is not.

See also: Socket table, 5-tuple

Socket table

The operating system's record of open network endpoints and the process identifier owning each.

Why it matters here

The table is sampled periodically and joined against captured packets. Reconnaissance measured the gap this leaves: of 12,249 connections observed opening and closing across two sessions, none lived less than the 250 millisecond sampling interval, so the race window is real but lands on traffic that does not matter, chiefly name resolution.

See also: Attribution, IP Helper, Socket table entry, Attribution index

References:

  • Microsoft, GetExtendedTcpTable and GetExtendedUdpTable. The interface fragcap reads. The table class selects the row shape; the owning-module classes carry a socket creation timestamp and the owning-process classes do not.

Socket table entry

One row of a socket table: a protocol, a local endpoint, a remote endpoint for TCP only, an owning process identifier, and the instant the socket was created when the platform reports one.

The absent remote for UDP is a property of the platform interface rather than a fragcap simplification, and specification section 8.4 forbids inventing one.

Why it matters here

The creation instant is what tells the previous owner of a reused port from the current one. A socket created after a packet cannot have owned that packet, so an entry that postdates the packet is not a candidate at all. Without it, a port reassigned between two snapshots attributes the new owner's identity to the old owner's traffic, confidently and silently.

Reconnaissance recorded the timestamp as a property of the TCP table. Slice S10 found it on both, which matters more for UDP: a UDP entry has no remote, so its key is the weakest of the two and a reused port is least distinguishable there.

See also: Socket table, 5-tuple, Attribution fidelity

Attribution index

The immutable value a lookup reads: a socket table snapshot, the image names resolved for the process identifiers in it, and the retention window's map of endpoints that have left the table.

The control thread builds a new one on each refresh and publishes it atomically. Capture threads read the current one without locking.

Why it matters here

Everything an answer can contain is in the index before the lookup begins. That is what makes attribution lookup unable to block packet acquisition: there is nothing on the lookup path to block on. An implementation that resolved an image name lazily would put an operating system call on the capture thread at the start of a session, which is exactly when the most sockets are opening at once.

See also: Socket table, Capture thread, Flow attributor

Retention window

The grace period, defaulting to thirty seconds, during which an endpoint that has left the socket table remains resolvable.

Measured from the instant the endpoint was last observed present in a table, not from the refresh that first noticed it gone. Those differ by up to one poll interval.

Why it matters here

Capture and socket table observation are not synchronized. A connection closing produces final packets processed after the socket has gone, so discarding attribution the moment an endpoint disappears would leave the tail of every connection unattributed.

The cost is that a retained answer can be wrong, in the one case where the port was reassigned inside the window. That is why such answers are marked: see attribution fidelity. It is also why the origin is exact. Measuring from the refresh that noticed the absence would make a thirty second window silently thirty-one, widening the exposure without saying so.

See also: Socket table, Attribution fidelity, Attribution

Refresh trigger

An event that causes the socket table to be re-read before the poll interval elapses.

Two exist. A process start matching a profile stage triggers one immediately, because a newly matched process is about to open sockets. An unattributed packet on a previously unseen endpoint triggers one too, rate limited to one per two hundred milliseconds.

Why it matters here

The rate limit is the load-bearing half. Without it, traffic fragcap will never attribute, which arrives at line rate and is unattributable no matter how often the table is read, would drive the table read rate. The limit is measured in wall-clock time rather than capture time for the same reason: replaying an hour of traffic in one second must not request thousands of reads.

The trigger is recorded rather than acted on, because it arrives on the capture thread, where reading a table is precisely what the publication contract forbids.

See also: Attribution index, Capture thread, Socket table

Dual-stack socket

An IPv6 socket bound to the unspecified address that also accepts IPv4 traffic, which the socket table reports under its IPv6 bind rather than under the address a datagram arrived on.

Why it matters here

Matching these is a judgement call fragcap makes deliberately. Reconnaissance found no focal title relying on one, so the rule is unexercised by them rather than wrong. Refusing to match would make a whole class of sockets silently unattributable, and a silent unattributable class is worse than an imprecise match that ranks below every exact one and still requires the port to agree.

See also: Wildcard bind address, Socket table entry

Process tree

The ancestry relation among processes, recorded at creation time rather than reconstructed from current state.

Why it matters here

Reconnaissance found chains deeper than the specification assumed: five levels for one focal title, six for the other with an anti-cheat launcher in the middle. One title runs three processes sharing a single image name and only the last holds sockets, so identifying the right process requires ancestry rather than image name. Matching on name alone binds to a process that never transmits and reports an empty capture as success.

See also: ETW, PID recycling, Launcher chain, Stage

PID recycling

The reuse of a process identifier by a new, unrelated process after the original exits.

Why it matters here

Recycling is why a process node is keyed by the pair of operating system identifier and start timestamp rather than by the identifier alone, and why ancestry must be captured live rather than walked afterward.

See also: Process tree, Synthetic process identifier

Synthetic process identifier

The session-local identity fragcap assigns to each process it observes, never reused within a session.

Distinct from the operating system process identifier, which is drawn from a reusable pool and is unique only among live processes.

Why it matters here

The distinction is what makes the process tree correct across PID recycling. The synthetic identifier is a node's identity; the pair of operating system identifier and timestamp is the lookup key into the tree. An implementation that collapses the two merges two unrelated processes into one node, and every descendant of the second then claims ancestry it does not have.

See also: Process node, PID recycling

References:

  • fragcap specification section 10.2. The tree's keying rule.

Process node

One process in the process tree, carrying its operating system identifier, its resolved parent, image path, command line, start and exit timestamps, ancestry provenance, and the profile stage it is bound to where one matched.

Why it matters here

Nodes are retained for the whole session after the process exits. Retention is what lets a packet arriving after its sender has terminated still be attributed, and specification section 5.4's observed chains are full of transient launchers that are already gone by the time the client matters.

See also: Process tree, Synthetic process identifier, Ancestry provenance

References:

  • fragcap specification section 10.2. The node's fields.

Ancestry provenance

Whether a process node learned its parent from a creation event or from the startup snapshot.

Why it matters here

The two differ in how much they can be trusted, and the difference is carried on the node rather than derived. A parent observed at creation is unambiguous; one read from a running process may name an unrelated process or nothing at all, because Windows records a parent identifier and then neither maintains it nor stops reusing the values. A consumer that cannot tell them apart treats a guess as a measurement.

See also: Process node, Startup snapshot, PID recycling

References:

  • fragcap specification section 5.3. Why creation-time ancestry is the only reliable kind.

Startup snapshot

The single enumeration of already-running processes fragcap takes when its watcher starts, so that targets running before fragcap began are present in the process tree.

Why it matters here

Taken after the event subscription, never before. Subscribing first can report one process twice, which the tree reconciles into a single node; snapshotting first leaves a window in which a process created in between is reported by neither source, and nothing downstream can detect that it is missing. It is also the only source of processes whose command line fragcap cannot obtain, because reading one from a running process needs a memory-read right the technique denylist forbids.

See also: Process tree, Ancestry provenance, ETW

References:

  • fragcap specification section 10.1. The snapshot establishes initial state; the event stream maintains it.

Trace session

A named ETW collection fragcap starts for itself, carrying the kernel process provider, and stopped when fragcap finishes.

Why it matters here

Never the machine-wide kernel logger, which exists once per machine. Contending for it would make fragcap fail whenever any other tool is tracing, and taking it by force would make fragcap the tool that silently breaks the operator's other instrumentation. Windows 8 and later permit several concurrent system loggers, subject to a small fixed limit, and exhausting that limit is reported with the platform's own reason rather than worked around.

See also: ETW, Lost event

References:

  • Microsoft Learn, Configuring and Starting a SystemTraceProvider Session.

Lost event

An event the kernel reported dropping before fragcap could read it.

Why it matters here

A lost event is not a lost packet. A packet's loss costs that packet; a lost process start event removes a node and silently orphans everything beneath it. That is why the channel between the trace consumer and its subscribers is unbounded rather than a bounded drop-oldest ring, and why a process tree built while anything was lost reports itself incomplete rather than presenting as whole.

See also: Trace session, Process tree, Drop-oldest

References:

  • fragcap specification section 10.1 and constitution principles P-4 and P-9.

Launcher chain

The sequence of processes between a user starting a game and the game client running, typically a platform client starting a publisher launcher which starts the client.

Why it matters here

The chain defeats detection that waits for the game executable to appear: by then the authentication exchange, frequently the most information-dense traffic of the session, has already happened. It also contains shims that hold no sockets at all.

See also: Process tree, Stage

Stage

A named position in a launcher chain that a game profile matches against, carrying a role and a lifecycle class.

Why it matters here

Stages are how fragcap stays game-agnostic while treating specific titles as first class. Adding support for a game means writing a TOML file, never modifying Rust.

See also: Game profile, Launcher chain, Lifecycle class, Terminal stage, Match predicate

Lifecycle class

What a stage declares about how long its process is expected to live, and therefore how its exit is treated: transient exits during the session and that exit is normal, session is expected to live for the session and its exit is significant, service may have been running before the session began and is never awaited during acquisition.

Why it matters here

Waiting for a service to start deadlocks, because it has already started. The class is also what makes a terminal stage meaningful: only a session process has an exit worth ending a capture on.

See also: Stage, Terminal stage, Launcher chain

Terminal stage

The one stage in a game profile whose exit ends the capture. At most one per profile, and its lifecycle class is always session.

Why it matters here

A terminal transient stage would end the capture at the moment a launcher hands off, which is the point the whole launcher chain exists to survive. Validation refuses it rather than leaving the mistake to be discovered in a short well-formed capture file.

See also: Stage, Lifecycle class

Match predicate

One condition a stage tests against a process start event: exe, an image name glob compared case-insensitively; path_contains; path_regex; cmdline_contains; and descends_from, an ancestor bound to a named role. All predicates a stage declares must hold.

descends_from resolves against the synthetic process tree rather than the operating system parent chain, which is what makes it reliable across a launcher that has already exited.

Why it matters here

Where an image name is not unique within a chain, descends_from is required rather than advisory. See ambiguous image match for what happens when it is missing.

See also: Stage, Ambiguous image match, Process tree

Ambiguous image match

Two stages in one game profile whose exe patterns can match a common image name, where at least one of them declares no other match predicate. Validation refuses the profile and names both stages.

The decision is exact rather than approximate: two patterns over *, ?, and literals either can match a common name or cannot.

Why it matters here

A stage bound to the wrong process among several sharing an image name produces a capture that exits zero, is well formed, and contains no gameplay. One focal title runs three processes under one image name and only the last holds sockets, so this is a recorded case rather than a hypothetical. It is the configuration-side form of the loss constitution principle P-4 forbids: every packet is lost and none is counted.

See also: Match predicate, Stage, Launcher chain

Stage matching

The decision that binds an observed process to a stage. Each process start event is evaluated against every stage in the active game profile, and the process binds to the first stage, in declaration order, all of whose match predicates hold. Binding assigns the stage's role. Slice S12.

Why it matters here

Matching is a decision over the process tree and the profile. It opens nothing and touches no platform interface, so the whole of section 10.3 is tested against a scripted event stream with no capture driver, no elevation, and no game.

See also: Match predicate, Stage binding, Capture session

Stage binding

The association of a process node with the stage it matched and the role that stage assigns, recorded on the node. A node binds to at most one stage.

See also: Stage matching, Stage, Process node

Capture session

The run of one capture, moving through five states: Arming (opening the capture handle and attaching the process watcher before any target exists), Watching (armed, no target matched, discarding packets), Capturing (a stage has matched, packets retained), Draining (a stop condition met, buffer draining and sinks finishing), and Complete. Slice S12.

Why it matters here

Arming before the target is what keeps the launcher authentication exchange, which precedes the client, from being missed. The Watching to Capturing transition costs no setup because the handle is already open, so no traffic is lost at the boundary.

See also: Stop condition, Acquisition timeout, Stage matching

Acquisition timeout

The optional bound on how long a capture session waits in Watching for a target before completing without having captured. Measured from the instant the session was armed. When unset, the session ends instead by the duration bound or an operator interrupt.

See also: Capture session, Stop condition, Watch mode

Watch mode

The launch-agnostic capture path, reached since S054 through fragcap capture --process <image> (the dedicated watch verb it names was retired when the three capture verbs collapsed into one): fragcap arms its process watcher and sinks and captures the first process matching a target identity, however and wherever it was started, including one already running at arm (found in the startup snapshot). The identity is an executable name plus a path anchor (--path/--path-regex); a target that starts after arm is acquired on its start event, and one already running is acquired when the snapshot is folded in, both by runtime observation. Managed launch is a convenience layered on top, never the spine.

Why it matters here

The path anchor is matched against the full image path. A process starting after arm supplies one; the toolhelp startup snapshot supplies only the executable name, because reading a running process's path is the handle the no-handle posture of principle P-1 declines. So a path anchor disambiguates a target that starts after arm, an already-running target is attached by executable name alone, and where a path anchor cannot be checked against an already-running process fragcap says so rather than wait silently until the acquisition timeout.

Why it matters here

Watch mode is what makes a modded install launched from a mod manager, a standalone title, and every non-storefront game capturable at all, because it assumes nothing about origin. It is the runtime case a hint database marks launcher_mediated: the launch entry is a stub or publisher launcher, and watch mode attributes the socket-holding descendant. A watch that never sees its target gives up at the acquisition timeout with a named reason, never silently (constitution principle P-4).

See also: Acquisition timeout, Process watcher, Target, Startup snapshot

Stop condition

Any of the six events that ends a capture session: the elapsed duration bound, the byte or packet bound, the terminal stage exiting, all matched non-service processes having exited with no stage still awaited, an operator interrupt, or an unrecoverable sink error. The first to occur wins.

Why it matters here

Every stop condition produces the same orderly shutdown and a valid capture file. Uniform shutdown is what lets an operator read any capture the same way, including one they interrupted; an interrupt is a normal stop, not an abort.

See also: Capture session, Terminal stage, Lifecycle class

Profile schema version

The schema key at the top of a game profile, declaring which version of the file format it is written against. Currently 1.

A profile declaring an unsupported version is refused with one diagnostic naming the supported version, and the rest of the file is not reported on.

Why it matters here

The version is what makes strict key checking safe. Unknown keys are refused rather than ignored, because ignoring payloads = false written for payload = false hands the operator a capture containing contents they meant to exclude and says nothing. Refusing needs a way for the format to grow, and this is it. Reporting forty unknown-key faults when the real answer is that the profile is newer than the build would be misleading rather than merely unhelpful.

See also: Game profile, Profile resolution order

Profile resolution order

The four steps by which a profile reference becomes a profile, first match winning: an existing file at that path, then <ref>.toml in a profile directory given on the command line, then <ref>.toml in the user profile directory, then a bundled profile whose game.id matches.

A reference used in the last three steps must be a valid identifier and is refused before any path is joined to it. An explicit path is exempt, because an operator who types a path has named a file.

Why it matters here

User profiles shadow bundled ones by design, so a bundled profile that has drifted from a game update is corrected locally without waiting for a release. The identifier check happens before the join rather than relying on the open failing, because a check that depends on what is at the target is not a check.

See also: Game profile, Profile schema version

Packet source

The seam that acquires packets. A live capture backend implements it in slice S09; a replay source over recorded fixtures implements it in slice S04.

Why it matters here

Keeping acquisition behind a trait is what makes the pipeline testable offline, with no capture driver, no elevation, and no game running. Constitution principle P-3 forbids merging it with the flow attributor.

See also: Flow attributor, Sink

Flow attributor

The seam that resolves a flow key to the process owning it, by matching against the socket table.

Returning nothing means attempted and unresolved. The packet is retained and marked, per constitution principle P-4, never dropped.

See also: Packet source, Attribution, Socket table

Process watcher

The seam that reports process creation and exit, over ETW kernel providers.

Ancestry comes from creation-time events rather than from inspecting a running process, which is what lets fragcap reconstruct a launcher chain without a process handle. Constitution principle P-1 forbids handles carrying memory-read rights against a target.

See also: Process tree, ETW, Launcher chain

Sink

The seam that accepts captured packets and writes them somewhere: a file, a stream, or a ring buffer.

Sinks are independent of one another and of the pipeline, and a session may have any number attached. A sink that cannot accept a packet reports it, and the pipeline counts it in a named counter rather than aborting the capture.

See also: Packet source, .fcapng, Backpressure

Dissector

The seam for protocol dissection, declared in v0.2.0 with no implementations.

Fixing the shape before any protocol work begins prevents the eventual dissector layer from being retrofitted against types that were not designed for it.

See also: Sink

Replay source

A packet source that reads a recorded capture file rather than an interface. Half of what makes specification section 25.1's claim true.

Deterministic by construction: the same bytes yield the same packets, on every run and platform. That is the property golden comparison depends on, and a test whose input varies is a failure nobody can reproduce.

Why it matters here

It accepts a capture filter and applies nothing, and says so. Failing would break a pipeline that filters unconditionally; accepting silently would let a test believe filtering happened. Exhaustion is reported as the terminal closed condition rather than as a timeout, because a timeout means keep going and would spin forever on a finished file.

See also: Packet source, Scripted attributor, Fixture

Scripted attributor

A flow attributor that answers from a declared attribution script rather than a socket table. The other half of the section 25.1 claim.

It matches through the same attribution key derivation and wildcard bind allowance the real attributor will use, so a test that passes against a script is one that implementation has to satisfy. It cannot express an attribution the platform could never supply.

Why it matters here

The attributor seam carries no timestamp, because a real attributor reads a table that is already current. A scripted one has to be told what "now" is, and that is a method on the double rather than a widening of the seam: a test double is a poor reason to hand every real implementation a parameter it does not want.

See also: Flow attributor, Attribution script, Replay source

Attribution script

A text file declaring what a scripted attributor answers for each flow in each window of time.

The time dimension is the point. PID recycling and port reuse mean one local endpoint can belong to different processes at different instants, and without windows there is no way to test that short of a live machine and a stopwatch.

See also: Scripted attributor, Fixture corpus, PID recycling

Parse outcome

What header parsing concluded about one frame: either a flow key with an optionally determined direction, or a named parse rejection cause. Never silence.

An undetermined direction accompanies a successful parse rather than being a third outcome, because the frame was understood and one property of it was not.

See also: Parse rejection cause, Flow key, Direction

Parse rejection cause

The specific reason a frame produced no flow key. Twelve of them, a closed set, each with its own counter.

The set is separated exactly where the remedy differs. A short header means raise the snapshot length; a malformed header means a broken sender or a defect in fragcap; an unsupported EtherType means unexpected traffic; an unsupported link type means an unexpected capture backend.

Why it matters here

A packet that produced no flow key is retained and marked, never dropped, so a rejection is not loss. Constitution principle P-4 requires the cause be named and surfaced, and the set is closed so that adding a way to decline without adding a counter does not compile.

See also: Parse outcome, Parse statistics

Parse statistics

One counter per parse rejection cause, plus one for an undetermined loopback direction and one for a fragment identity table eviction.

Carried beside the capture and source counters rather than folded into them, and contributing to no drop total, because no parse outcome is a drop. There is deliberately no counter for a successful parse: it is the captured count less the rejections, and a stored total can drift from its parts.

See also: Parse rejection cause, Backpressure

Master target schema

The single versioned JSON Schema (Draft 2020-12) that governs every machine-readable targeting and attribution artifact: a game profile, a target hint record, a user-authored package, and a hint-database export. Introduced by issue #75. Embedded in the binary as the single source of truth, published under docs/schema/, and validated one-off with fragcap schema validate.

Why it matters here

The schema expresses structural conformance only: types, required keys, enum ranges, unknown-key refusal, and the kind and schema discriminators. The semantic invariants of profile validation (acyclic ancestry, at most one terminal stage, role reachability, no ambiguous image match) are not expressible in a schema and stay in the profile-load path. A document that passes schema validate asserts structural conformance, nothing more.

See also: Target artifact kind, Fidelity tier, Provenance, Game profile

Target artifact kind

The closed discriminator on every artifact governed by the master target schema. One of profile (the strict, authoritative description the pipeline runs against), package (a hand-authored or community-submitted profile, highest precedence), hint (a loose, partial heuristic guess), or export (the JSON projection of hint-database rows). Profile and package share one strict shape; hint and export share one loose shape.

See also: Master target schema, Target hint record

Hint database

The embedded store of known game binaries and launch patterns that seeds the resolution cascade at precedence 2, emitting one target hint record per title. It is never a source of truth: every record it emits is heuristic-unverified (see fidelity tier), and a live runtime observation always overrides it. The store is populated across three independent seeding tiers and exports to the export target artifact kind, which an unmodified schema validator reads.

Why it matters here

The database holds auto-generated guesses at scale, not curated facts. Stamping every record heuristic-unverified is what keeps a large, cheaply-seeded corpus from ever outranking what fragcap actually observes at runtime (P-9).

Since the two-store split it spans two files: the catalog store, which is shipped, and the local store, which is the user's, and it consults the local store first.

See also: Catalog store, Local store, Target hint record, Seeding tier, Resolution cascade, Target artifact kind

Catalog store

The ShruggieTech-shipped store (catalog.db) that seeds the resolution cascade: the public catalog, launch metadata, and engine attribution tiers, every row heuristic-unverified. It is disposable and replaced wholesale by a catalog refresh, so it holds no user data, and it lives in the per-user data root alongside the local store, consulted after it.

Why it matters here

Splitting the shipped catalog from the user's own store makes a refresh a plain file replacement, with no merge and no possibility of losing learned data. One file is ours and disposable; the other is the user's and is never touched by an update.

See also: Local store, Hint database, Seeding tier

Local store

The user-owned store (local.db) that accumulates data learned or authored on this machine: the launch executables learned from the local application-info cache, and the target and preference data later work adds. It is never shipped and never replaced by a catalog refresh, and the resolution cascade consults it before the catalog store.

Why it matters here

Learned launch data is specific to this machine's own installs, so it is the user's, and it outranks the shipped catalog at resolution. Keeping it in its own file is what lets a catalog refresh leave it byte-identical.

See also: Catalog store, Hint database, Application-info cache

Seeding tier

One of the three independent sources that fill the hint database, each owning its own columns so it can run and resume without disturbing the others: the public catalog (application id and name), the launch metadata (the launch array and the launcher-mediated flag), and the community engine data (the engine attribution). The database records a per-tier seed state, which tier last ran and a resume cursor, so a later fetch resumes rather than rebuilding the whole corpus.

See also: Hint database, Launch array, Engine attribution

Catalog seeder

The seeding tier that fills the hint database's public-catalog columns (application id, name, and popularity metrics) from a catalog source. It reads a source's entries, applies the corpus gate, merges the admitted titles by application id (leaving other tiers' columns intact), records a resume cursor after each page, and returns a seed summary. Its logic is driven in tests by an offline fixture source and in production by a read-only HTTP source; the two share one contract, so the seeder is tested without a network.

See also: Corpus gate, Seed summary, Seeding tier, Hint database

Corpus gate

The rule the catalog seeder applies to decide whether a catalog entry belongs in the corpus: it admits a title only if the title is a game and its review count is known and at or above a configurable threshold. The Steam app-list universe is large and mostly noise; the gate scopes the corpus to the titles that matter. A title whose popularity is unknown is excluded, not admitted on a guess (P-9), and every exclusion is counted in the seed summary, never a silent omission.

See also: Catalog seeder, Seed summary

Seed summary

The truthful account a seeder run returns, shared by the catalog seeder and the engine seeder: how many titles it fetched, wrote, excluded, saw as a within-run duplicate appid (merged once, not written twice), and failed to parse. The counts reconcile (fetched equals written plus excluded plus duplicates plus failed), so a corpus that dropped what it could not handle, or a repeated title that would otherwise overstate the total, cannot read as complete. This is the seeding-time form of the No Silent Loss principle (P-4).

See also: Catalog seeder, Engine seeder, Corpus gate

Launch-data accumulation

The local, per-user process by which each copy of fragcap learns its own Steam titles' launch executables from the machine's own application-info cache into the user's private hint database, accumulating across runs. It walks the installed library, and for each title reads the cache's launch configuration into the launch seeding tier only when the title's data is missing or its cache change-number is newer than the one the store recorded (change-number staleness), skipping titles already current so repeat runs stay cheap. It is passive: a local file read, no network, no process handle (P-1), and it ships nothing, so every learned fact stays on the machine that learned it. Pooling accumulated data across users is deferred (issue #94).

Why it matters here

Baking a maintainer's launch data into the shipped database would leak which games the maintainer owns. Accumulation moves the launch tier onto the end user's own machine, so the shipped database carries only public catalog and engine data and no one's library is ever disclosed.

See also: Application-info cache, Accumulation account, Launch array, Hint database

Accumulation account

The reconciled record a launch-data accumulation run returns: how many installed titles it considered and, for each, whether its launch data was written, skipped as already current, failed to parse, or yielded nothing to store. The per-title outcomes reconcile to the number considered, so a walk cut short or one that skipped unreadable titles cannot read as complete; a file-level parse fault is surfaced on a separate axis rather than folded in and hidden. This is the accumulation-time form of the No Silent Loss principle (P-4).

See also: Launch-data accumulation, Seed summary

Engine seeder

The seeding tier that fills the hint database's engine attribution columns (engine name, source pcgamingwiki, and confidence) from an engine feed, keyed by Steam application id. It reads a feed's entries, writes an engine by application id for each title that resolves to a single unambiguous engine (leaving other tiers' columns intact), records a resume cursor after each page, and returns a seed summary. Unlike the catalog seeder it applies no corpus gate: it enriches whatever titles the feed names an engine for. A title with no engine, or an ambiguous one, is left absent and counted excluded, never guessed (P-9).

Why it matters here

The engine seeder writes a within-field engine attribution onto a row without touching the catalog name or the launch array the other tiers own, and it never lowers the record's overall fidelity tier: a seeded engine stays heuristic-unverified however confident the field grade. Absence is honest; a guessed engine would be a hint worn as a fact (P-9).

See also: Engine attribution, Engine feed, Seed summary, Seeding tier, Hint database

Engine feed

The source abstraction the engine seeder reads from: it yields, per title, an application id and either a single resolved engine (a name and a within-field confidence grade) or no engine. Its logic is driven in tests by an offline fixture feed and in production by a read-only PCGamingWiki query source; the two share one contract, so the seeder is tested without a network. It is named a feed, not a source, to stay distinct from the engine.source provenance token an engine attribution carries.

See also: Engine seeder, Engine attribution

Target hint record

A loose, partial artifact emitted by a heuristic provider or the hint database. It may omit fields a game profile requires, but it MUST carry a fidelity tier and provenance. A hint that does not declare its trust level is refused: an undeclared guess is exactly the guess-worn-as-fact the schema exists to prevent.

See also: Fidelity tier, Provenance, Target artifact kind, Launch array, Engine attribution

Launch array

The ordered list of a Steam title's launch configurations, carried on a target hint record as its launch field. Each entry records one config.launch configuration: an optional operating-system, architecture, launch-type, and beta-branch filter, a required executable, and optional arguments and a description. The array is carried whole and is never reduced at seeding time to a single "the game binary"; deciding which entry (or which descendant of the invoked one) holds the sockets is the resolution cascade's runtime job, not a seeding-time transformation.

Why it matters here

For a launcher-mediated title the entry Steam invokes is a publisher launcher, not the socket-holding client, so flattening the array to the invoked executable would record the launcher as the game. Preserving the array with its filters intact keeps the honest, unreduced fact for the resolver (P-9).

See also: Launcher-mediated, Target hint record, Resolution cascade

Launcher-mediated

A flag on a target hint record marking a title that Steam starts through a publisher launcher, which then starts the real client (for example ESO or The Division 2): Steam -> Launcher.exe -> Game-Win64-Shipping.exe. The invoked launch array entry is the launcher, not the socket holder, so a launcher_mediated hint is a second signal into the same stub-to-client hop the engine rule already performs, resolved at runtime rather than assumed at seeding time.

See also: Launch array, Engine rule, Target hint record

Engine attribution

A target hint record's guess at a title's engine, carried as its engine field: an optional engine name, a source (pcgamingwiki, exe_heuristic, or depot_filename_rules) naming where the guess came from, and a confidence (confirmed, high, medium, low, unknown). A failed lookup leaves the field absent rather than present with a fabricated value.

Why it matters here

Engine confidence is a within-field grading of one heuristic guess, not a rung on the record's fidelity tier ladder. The record fidelity says how much to trust the record as a whole; the engine confidence grades one field inside it. Keeping them separate stops a low-confidence engine guess from silently moving the record's overall trust, which is the same P-9 honesty the fidelity model exists for. The engine source is likewise distinct from the record's provenance source, which names where the whole record came from.

See also: Fidelity tier, Provenance, Engine rule, Target hint record

Fidelity tier

The structured, ordered trust level carried by every targeting artifact: authored (a person wrote it), verified (confirmed correct), heuristic-unverified (a machine guessed it), or observed (confirmed against a live capture). The resolver reads it; the instrument never fabricates it.

Why it matters here

Fidelity is data, not a comment, precisely so the tool can act on it: refuse to treat a heuristic as verified, surface it to the operator, and gate a submission. Constitution principle P-9 requires that a guess be presentable as a guess and never as a fact.

See also: Master target schema, Provenance

Provenance

The structured record of where a targeting artifact came from: a source (for example steam-appinfo, engine-rule, or user) and an optional seed time. Required on a target hint record and on a hint-database export, so an unverified artifact always names its origin.

See also: Fidelity tier, Target hint record

Provider

A source that can answer "what is this game's target identity?" within the resolution cascade. Each provider yields either a target stamped with its fidelity tier and provenance, or no answer, and occupies a fixed position in the cascade's precedence order. Introduced by issue #77. The built-in providers are the profile lookup, the hint database, the engine rule, the platform walker, and runtime observation.

See also: Resolution cascade, Target resolver, Target, Fidelity tier, Engine rule

Target

The resolved answer the resolution cascade hands to the capture pipeline: an identity to capture (an executable image name plus optional path anchors, per the match predicate set), the fidelity tier of the source that produced it, and its provenance. Distinct from a game profile: a profile is one way to back a target, the authored or verified way, but runtime observation produces a target with no profile behind it at all.

See also: Resolution cascade, Provider, Fidelity tier, Match predicate

Target resolver

The component that consults its providers in a fixed precedence order and returns the highest-precedence available target, or a distinct not-resolved outcome when none answers. The order is total and imposed: when more than one provider can answer, the higher-precedence one wins regardless of the order the providers were registered in.

Why it matters here

The resolver ranks by trust, not by which provider happened to be consulted first. An observed answer is never presented above a verified one, and a not-resolved outcome is named rather than silent, so a capture is never armed against nothing (constitution principles P-9 and P-4).

See also: Resolution cascade, Provider, Fidelity tier

Resolution cascade

The launch-agnostic mechanism by which fragcap decides what to capture for a game: a set of providers of varying trust, consulted by the target resolver in precedence order, each answer stamped by fidelity tier. Introduced by issue #77. It separates the question of what to capture from how a game is launched, because the only durable fact is that at runtime a process exists that is the game and holds the sockets. Distinct from the profile resolution order, which is the narrower first-match lookup of a single profile inside the profile provider.

See also: Provider, Target resolver, Target, Profile resolution order, Engine rule

Engine rule

A provider that recognizes a game's socket-holding client from its game engine's documented on-disk install layout, with no per-title data. Many games ship a thin launcher stub in the install root whose only job is to relaunch the real networked client; before the game has run, only the on-disk layout distinguishes the two. An engine rule keys on that layout: Unreal Engine's shipping client is a *-Win64-Shipping.exe under a Binaries\Win64 directory, Unity's player sits beside a *_Data directory and a UnityPlayer.dll or GameAssembly.dll, Godot's binary sits beside a *.pck archive, and Ren'Py ships a renpy directory and .rpa archives. These are the same class of filename evidence the Steam database's open detection ruleset (SteamDatabase/FileDetectionRuleSets, MIT) uses to attribute an engine from depot file names alone; fragcap tracks the subset that also names the client executable, so the rules stay aligned with a maintained source. It reads the filesystem only, opening no process handle and reading no process memory (constitution P-1), and it ignores post-run artifacts such as per-user AppData, which do not exist before the first launch. Introduced by issue #77, filled in by slice S029; its provenance source is engine-rule.

Why it matters here

An engine rule is a heuristic, so every answer it produces is stamped heuristic-unverified and never higher (P-9). When a layout is recognized but more than one candidate client matches, the rule declines rather than pick one arbitrarily, and the cascade falls through to runtime observation, which disambiguates once the game is running. A directory it cannot read is not the same as an absent layout: an incomplete scan could hide a second candidate, so the rule declines and records the unreadable path rather than resolving from a partial view (P-4).

See also: Provider, Provenance, Fidelity tier, Resolution cascade, Platform walker

Technology detection

The surface that reports the technologies present in a game's install directory (its game engine, anti-cheat, SDK, emulator, container, and launcher) by matching a detection ruleset's path patterns against the install's file paths, using file names and relative paths only. Distinct from the engine rule, which reads the same install layout only to name the socket-holding client: technology detection labels what a game is built on and what watches it, and does not choose a capture target. Each finding pairs a technology name with the marker path that revealed it and is stamped heuristic-unverified. Introduced by slice S031; the categories are engine, anti_cheat, sdk, framework, emulator, container, runtime, and launcher.

Why it matters here

Technology detection reads file paths only: it opens no process handle, reads no process memory, reads no file content, and makes no network call (constitution P-1). A detected anti-cheat is surfaced as a user-safety and consent signal so the operator knows what watches a game before capturing it; fragcap detects it and never interacts with it. A ruleset pattern the regex engine cannot compile is a counted, surfaced skip rather than a silent drop, so reduced coverage is visible (P-4), and a finding is a heuristic guess from a path, never asserted as fact (P-9).

See also: Detection ruleset, Marker path, Engine rule, Anti-cheat

Detection ruleset

The open SteamDB SteamDatabase/FileDetectionRuleSets ruleset (MIT), the maintained source behind SteamDB's technology attribution, which recognizes game engines, anti-cheat systems, SDKs, emulators, containers, and launchers from depot file paths alone. fragcap vendors it verbatim, pinned to an upstream commit and hash-locked, and applies its direct category sections to a local install for technology detection. The engine rule tracks a hand-written subset of the same ruleset (the part that also names the client executable).

See also: Technology detection, Engine rule

Marker path

The relative install-directory path of the file or directory whose name matched a detection ruleset pattern, carried on a technology detection finding as the auditable evidence for it. A finding names one representative marker even when several files matched the same technology, so the report is one line per technology, not one per file.

See also: Technology detection, Detection ruleset

Platform walker

A provider that turns a storefront's installed library into cascade answers. It enumerates the storefront's installed titles and their install directories (Steam's libraryfolders.vdf and appmanifest files, in the first walker), and it contributes to the cascade in two ways: it makes a title's install directory available to the resolver so the higher-precedence engine rule can name the socket holder from layout, and, when the engine rule does not recognize the layout, it answers at its own lower precedence by classifying the install directory's executables into a single client. It reads the filesystem and the registry only, opening no process handle and reading no process memory (constitution P-1). Introduced by issue #77, filled in by slice S030; its provenance source is steam-library, naming the library walk and install-directory classification it performs and not a source it does not read.

Why it matters here

The walker declines rather than guess. It resolves only when exactly one plausible client executable remains after dropping installers and launcher stubs; zero, or several, is a decline, and the cascade falls through to runtime observation, which resolves the game from the live socket-holding process. Selecting a client by size among several is the coincidental heuristic that proved unreliable, so the walker, feeding automatic capture, does not guess where the human-reviewed scaffold does (constitution P-9). A directory it cannot read is surfaced, not treated as an absent one (P-4).

See also: Provider, Resolution cascade, Engine rule, Target, Provenance

Hint provider

A provider that answers the resolution cascade at precedence 2 from the hint database. Given a Steam application id carried on the resolution request, it reads the one stored row and, when that row names a single usable Windows client executable, answers with a target keyed on that executable, carrying the launcher-mediated flag and the row's engine attribution name as facts. It reads the embedded database only, opening no process handle, reading no process memory, launching nothing, and making no network call (constitution P-1). Introduced by issue #78, filled in by slice S037; its provenance source is hint-db, the same name the database's export projection uses, so a resolution answer and an export name the store's origin identically and never claim a source not read. Because the database may be built out or absent, the provider is registered only when the operator supplies a present database, and its absence changes nothing.

Why it matters here

The hint provider answers only when the row names exactly one usable client, and it never guesses. A sparse catalog-only row, an engine-only row with no launch executable, a row whose launch entries name more than one distinct executable, and a launcher-mediated row (whose launch executable is the publisher launcher, not the socket-holding client) are all declines, so the cascade falls through to the engine rule, the platform walker, and runtime observation rather than arming a capture against a launcher or a guessed process (P-4). An ambiguous decline records why, so a not-resolved outcome can explain itself. Every answer is heuristic-unverified and a live observation always overrides it (P-9).

See also: Provider, Hint database, Resolution cascade, Engine rule, Fidelity tier, Provenance

Non-profile capture path

The fragcap capture --target branch that captures a target the resolution cascade resolved without a game profile. When the selected target carries a Steam anchor, its install root is looked up from the anchor's app id and the engine rule, the platform walker, or runtime observation resolve a client identity, from which capture synthesizes a one-stage identity and captures through the same launch-agnostic engine an authored profile used. It is what activates the cascade's install-layout providers for capture rather than leaving their answers at a dead end. Introduced by slice S032; S054 routed it through capture --target when the ad-hoc run --install-dir/--steam inputs were retired.

Why it matters here

The synthesized identity is stamped heuristic-unverified, never authored, because it was resolved by a heuristic rather than typed by an operator (P-9). It reaches the target through the same passive engine as every other capture: no process handle is opened and no process memory is read (P-1). An install location the cascade cannot resolve to a single client (an unrecognized layout, an ambiguous one, an unreadable tree, or a Steam app id that is not installed) is a surfaced command failure that captures nothing, not a silent empty capture (P-4).

See also: Resolution cascade, Target, Engine rule, Platform walker, Fidelity tier

Target entry

A capture target stored as a row in local.db rather than as a profile file. Carries a stable identifier, a handle, a display name, a classification and the source that assigned it, a fidelity, and the launch entries, install root, provenance, and evidence carried whole. Introduced by slice S051.

Why it matters here

Making a target a row rather than a file removes the file format, the directory search order, and the up-front schema a user used to need before capturing anything. Every source that produces a target (interactive authoring, platform walking, directory scanning, runtime observation) writes the same row in the same store, read by the same resolution path (P-10).

See also: Handle, Stable identifier, Fidelity ordering, Attribution

Handle

The unique, human-readable selector for a target entry, derived deterministically from its name by a fixed normalization (strip decorative symbols, NFKD, strip combining marks, lowercase, delete apostrophes, collapse runs outside [a-z0-9] to a single underscore, trim, truncate to 64). Introduced by slice S051.

Why it matters here

A handle is never purely numeric, because a bare integer is a row-index selector; a name that would normalize to digits falls back to the executable stem, then to target_<n>, and a collision suffixes the new item _2, _3. The fallback never errors and never loops.

See also: Target entry, Anchor

Anchor

A platform-scoped title reference (a Steam app id, an Epic catalog item id, a GOG product id) rendered as a canonical prefixed string such as steam:2221490. The sole input to an anchored stable identifier. Introduced by slice S051.

See also: Stable identifier, Target entry

Stable identifier

The 63-bit value identifying a target entry across registrations and exports. Anchored: the low 63 bits of BLAKE3 over the canonical anchor, so independent registrations of one title collide on identity and merge. Unanchored: a random 63-bit value, replaced by the anchored value (and kept as a superseded alias) when the target later gains an anchor. Whether an entry is anchored is read from its anchor, not from a bit of the identifier. Introduced by slice S051.

Why it matters here

The identifier derives only from the anchor, never from the name, handle, or install path, so two entries built independently from the same anchor are the same entry. It is the merge key on import and the durable, machine-facing selector (--id).

See also: Anchor, Superseded alias, Handle

Superseded alias

A former stable identifier retained on a target entry after the entry gained an anchor and adopted the anchored identifier. The superseded value still resolves to the merged entry and is never reissued. Introduced by slice S051.

See also: Stable identifier, Target entry

Fidelity ordering

The rule that the resolution cascade's store read prefers the higher fidelity tier among competing answers: authored beats verified beats heuristic-unverified beats observed. A local target entry resolves at its own fidelity; a catalog.db row always answers heuristic-unverified; a runtime observation may promote a match to verified. Introduced by slice S051.

Why it matters here

Fidelity is a column the resolver reads, not a convention spread across crates (P-10). The four declines the store read preserves (a sparse row, an engine-only row, a launcher-mediated row, and a row naming more than one distinct client) keep it from naming a launcher as the game or guessing among clients (P-9).

See also: Fidelity tier, Target entry, Resolution cascade

Discovery source

An origin of capture candidate targets, expressed as the one TargetSource seam: a stable name, a discover operation yielding candidates plus a discovery account, and a default fidelity tier it stamps. Steam, the known-roots source, a directory source, and an interactive source are all instances. Introduced by slice S052.

Why it matters here

Single-target authoring and bulk platform walking are the same operation at different batch sizes (P-10): adding Epic, GOG, Xbox, Battle.net, or an emulator ROM directory is a new implementor of this seam with no downstream change.

See also: Candidate target, Discovery account, Discovery tier

Candidate target

What a discovery source produces: what was found (a filesystem path or a platform identity such as a Steam app id), a display name, the fidelity its source stamped, and any classification joined from the catalog store. It is not yet a stored target entry; a candidate becomes a durable entry through the entry model only when the user acts on it (captures or selects it). Introduced by slice S052.

See also: Discovery source, Target entry

Discovery tier

One of the three v0.5.0 layers a discovery source belongs to, ordered by how directly it names a game: tier 1, platform walkers (Steam); tier 2, the known-roots source; tier 3, the user-pointed directory source and interactive source. Exhaustive enumeration of every executable on the machine is deliberately not a tier: a normal machine carries thousands of non-Windows executables that would bury the game. Introduced by slice S052.

See also: Discovery source, Known-roots source

Known-roots source

The tier-2 discovery source that walks a fixed, hard-coded list of directories that only ever contain games (the Epic, GOG, Riot, Battle.net, Ubisoft, EA, Origin, Xbox, and Steam-library roots), across every eligible fixed volume. It classifies each directory by shape through the descent contract (descent stop-on-hit) rather than a curated per-title list. A container verdict prevents an organizational directory from being emitted as one title and requests bounded descent to its children. Introduced by slice S052.

Why it matters here

A machine with no Steam still lists games whenever a known root exists, and a second or third drive is walked as readily as the system drive. Which volumes are walked is governed by the volume eligibility table.

See also: Volume eligibility table, Descent stop-on-hit

Directory source

The tier-3 discovery source that takes one path a user points at and yields at most one candidate target for it. It asserts no classification, since the user vouches for the location, not for what the tool should call it. Introduced by slice S052.

See also: Interactive source, Candidate target

Interactive source

The tier-3 discovery source that wraps a directory source with a human confirmation step: an accepted candidate is stamped at authored fidelity because a human vouched for it; a rejected one is counted declined, never lost. Introduced by slice S052.

See also: Directory source, Fidelity tier

Discovery account

The truthful per-run tally a discovery source returns alongside its candidates, mirroring the seed summary: every item considered lands in exactly one named outcome (produced, parse-failed, declined, not-a-game, container-descended, container-descent-truncated, volume-skipped, access-error) and the outcomes reconcile to the number considered. Introduced by slice S052; the two container outcomes were added by slice S077.

Why it matters here

A discard path added later with no counter fails the conservation check rather than dropping a candidate silently (P-4). An excluded volume's skip is counted and surfaced, so the eligibility decision is auditable.

See also: Seed summary, Discovery source

Volume eligibility table

The persistent, user-editable allowlist in the local store naming which fixed volumes the known-roots source may enumerate. It is an allowlist rather than a denylist because a static denylist cannot recognize a userspace or FUSE mount that reports itself as an ordinary fixed drive. On first run it is seeded with the fixed volumes then present; afterward a later-appearing or misreporting volume is walked only after an explicit user opt-in. Each volume is keyed on a stable identity (its volume GUID path), not its reassignable drive letter. Introduced by slice S052.

Why it matters here

Widening the walk to an unseen volume without opt-in, or keying eligibility on the drive letter so a reassigned letter inherits a prior volume's decision, are the failures the allowlist and the stable identity exist to prevent (P-9).

See also: Known-roots source, Local store

Container verdict

The classification outcome for a directory whose observed findings name more than one distinct engine product. The directory is treated as an organizational container, not emitted as one candidate target, and descended through while the known-roots shallow bound permits. Repeated markers for one engine and anti-cheat or DRM findings do not establish this verdict. Introduced by slice S077.

Why it matters here

A container verdict prevents one aggregate row from making a false claim about a title and hiding every actual game below it. If the depth bound prevents descent, the discovery account and warning report that reduced coverage rather than claiming discovery completed.

See also: Known-roots source, Discovery account, Descent stop-on-hit

Descent stop-on-hit

The rule the known-roots source walk follows: test each directory for a game signature and, on a title hit, emit one candidate target and stop descending into that directory's subtree. A container verdict is the explicit exception: emit nothing and continue bounded descent. Never enumerate a directory's executables first and then ask whether each is a game. The signature matcher itself is a separate seam (slice S053); slice S052 introduced the descent contract and slice S077 added the container-aware correction.

Why it matters here

Performance is load-bearing: stopping on a hit is what keeps the walk from descending into a game's thousands of asset files, and testing directory shape before executables is what keeps it from enumerating every binary on the machine.

See also: Known-roots source, Candidate target

Unresolved launch chain

The launch information a target carries when the process that holds its sockets is not yet known: the marker an interactive targets add writes when the user answers no or unsure to whether the pointed-at executable holds the sockets. An entry with an unresolved chain names no client, so its capture readiness is needs a target, and a capture that observes the real holder can promote it to a resolved chain at a higher fidelity. The tool never fills the chain with a socket holder it did not observe.

Why it matters here

The unresolved marker is the honest record of a genuine unknown. Guessing the socket holder and presenting the guess as a resolved chain would be the instrument lying about what it observed; leaving the chain unresolved keeps the answer truthful until a capture supplies it.

See also: Stable identifier, Anchor

Launch-and-observe

The capture mode that turns a target with an unresolved launch chain into a capturable one: rather than refuse a target that names no client, fragcap builds a profile from the executable the user did point at, captures, and watches which process actually holds the sockets. The observed executable becomes a launcher stage and the process that descends from it and holds the sockets becomes the terminal client stage.

Why it matters here

It closes the loop opened by an unsure or no authoring answer. Before it, such a target was a dead end: registerable but not capturable. The mode captures the game the operator meant while learning, from the capture itself, which process to name next time.

See also: Unresolved launch chain, Observed socket-holder, Capture-time promotion

Observed socket-holder

The process image a launch-and-observe capture attributed the most packets to: the dominant socket-holding process the run actually saw, as opposed to any the operator guessed. It is the image a capture-time promotion records as the resolved client.

Why it matters here

It is the fact a promotion is built on. Choosing the dominant image by a total order over the per-image tally makes the choice the same on every run over the same traffic, so a promotion is a reproducible observation rather than a coin flip. A run that observes no holder promotes nothing.

See also: Attribution, Socket table, Capture-time promotion

Capture-time promotion

Rewriting a stored target's unresolved launch chain to a resolved client after a capture observed its real socket holder, and raising the target's fidelity to verified. It happens only when a run observed an observed socket-holder; a run that observed nothing leaves the target exactly as it was.

Why it matters here

It is how a target improves itself by being captured. The promotion is guarded by observation: fabricating a resolved client the run never saw would be the instrument lying about what it observed, so an unobserved run writes nothing and the target waits for a run that sees the game.

See also: Launch-and-observe, Observed socket-holder, Unresolved launch chain