Strata · Classification Lab · Methodology
The operational core of the doctoral team. The agent code (regrader.js) is the
operationalization of this document. If a definition changes here, the constant changes
there, and the dataset stays reproducible. This file is the thing a committee or a
reviewer reads first, and it is the thing the agent must never silently contradict.
1. The research setting
A classification scheme is normally studied after the fact, from its finished state, with the negotiation that produced it already invisible. A version-controlled repository is a rare exception: it is a classification scheme whose every revision is dated, attributed, and recoverable. We can watch a taxonomy be argued into shape over time, with timestamps.
That is the contribution. Not a new theory of classification, but a setting in which an existing theory becomes measurable. The directory tree of a working project is a living filing system, and its commit history is a complete record of every refiling.
Theoretical anchor: Bowker and Star, Sorting Things Out (1999). Three of their constructs are directly observable here:
- Infrastructure as classification. Categories are not given; they are made, and the making is work. Each regrading event below is an instance of that work, dated.
- Torque. The friction when a scheme and the reality it sorts pull against each other. Reclassification is torque being resolved. The rate and clustering of regrading events is an empirical proxy for torque over time.
- Residual categories. The
misc, thetmp, theother: where things go when they do not fit. Residual load (Section 4) is a direct, continuous measurement of this.
2. Core constructs
| Construct | Operationalization |
|---|---|
| Classification scheme | The directory tree at a given commit |
| Category | A directory path. Root is '' |
| Item | A file |
| Assignment | A file's immediate parent directory |
| Depth | An item's directory nesting; a category's path-segment count |
| Snapshot | The full scheme at one sampled commit (git ls-tree -r) |
The scheme is read directly from git rather than reconstructed from the Bedrock event log, because the analysis needs exact tree states and Bedrock stores a flat list of changes, not materialized states. The Lab reads source and writes its derived tables back into the same Bedrock database, so other agents can read its verdicts.
3. The regrading event typology
A regrading event is an observable act of (re)classification, attributed to the commit that caused it. Eight kinds, in two families.
Rename-derived (detected from git's -M rename tracking, --name-status):
- rename_in_place — item renamed, same category. Relabeling without reclassifying.
- relocation — item moves between categories, same depth, no residual transition.
- promotion — item moves to a shallower depth.
- demotion — item moves to a deeper depth.
- residualization — item moves into a residual category from a non-residual one.
- de_residualization — item moves out of a residual category into a non-residual one.
Snapshot-derived (detected by diffing consecutive snapshots):
- category_creation — a category with no prior existence now holds items.
- category_dissolution — a category that held items now holds none.
Priority rule
A single move can satisfy several definitions at once (a relocation that is also a depth
change that is also a residual transition). The headline kind is assigned by specificity,
most specific first:
residual transition > depth change > plain relocation
from_category, to_category, and depth_delta are recorded on every row regardless of
the headline. The nuance survives the label, so an analyst can always re-aggregate. For
example, a de_residualization that also went two levels deeper is labeled
de_residualization with depth_delta = +2, and can be counted either way.
Not stored as primitives (analysis layer)
- category_rename (a whole directory renamed) surfaces as N relocations sharing a commit and a common old-prefix to new-prefix mapping. Collapse in analysis, do not store as a primitive, to avoid double counting.
- merge / consolidation and split / differentiation are windowed patterns over the primitives above, not single events. Computing them requires a window and a threshold, and both are judgment calls; they belong in the analysis, with their parameters declared, not in the detector. Claiming them as primitives would overstate detection precision.
4. Snapshot metrics (the longitudinal variables)
One row per sampled commit:
- category_count — number of non-empty categories. Breadth of the scheme.
- file_count — items under management.
- max_depth and mean_depth — these diverge, and the divergence is informative. A scheme can deepen in one branch while flattening overall.
- residual_load — fraction of items living in residual categories. The headline measurement of Section 1's residual-category construct.
5. The residual lexicon (the key validity parameter)
The single most consequential choice in this design is which directory names count as
residual. Get it wrong and residual_load measures nothing. It is therefore an explicit,
versioned, two-tier parameter, not a buried constant.
- Core (default on): genuine "does not fit" buckets in Bowker and Star's sense.
misc, temp, tmp, other, stuff, junk, unsorted, uncategorized, scratch, sandbox, draft, wip, todo, legacy, archive, old, deprecated, backup, and close variants. - Soft (
--soft-residual, default off): contested terms that are legitimate categories in many codebases.util(s), helper(s), common, shared, lib(s), vendor, core.
The soft tier is off by default because including lib or shared as "residual" would
inflate the load and weaken validity. Every reported residual_load figure must declare
which tier produced it. The recommended practice is to run both and report the pair as a
sensitivity analysis; if a finding holds under core-only and core-plus-soft, it is robust
to the contested boundary.
6. Detector provenance and known properties
Honest limits, because the methodology section is judged on what it admits, not what it hides.
- Rename detection depends on git's similarity heuristic (
-M). A file rewritten beyond the similarity threshold in the same commit as its move will read as a delete plus an add, i.e. a dissolution-and-creation rather than a relocation. Thesimilarityfield is stored so these can be inspected and the threshold's effect studied. - Transient empties. A directory that empties and refills across two sampled commits
registers a dissolution followed by a creation. This is arguably correct (the category did
cease), but it is also a source of churn. Use
--sample=allwhen attribution must be exact. - Sampling and attribution. Snapshots are sampled (
all/daily/weekly). Rename-derived events are always exact (attributed to their actual commit). Snapshot-derived events under coarse sampling are attributed to the sampled commit, which bounds but does not pinpoint the moment of change.allremoves this gap at the cost of more snapshots. - Mainline only. Snapshots follow
--first-parent, so the scheme is read along the mainline rather than inside feature branches. This is a deliberate choice: it measures the scheme as it was actually published, not every transient arrangement on a branch.
7. Reproducibility
The agent is deterministic given a repo and its parameters. Every output file records the
parameters that produced it (params: { SAMPLE, SOFT }). The definitions in this document
and the constants in regrader.js are the only degrees of freedom, and they are versioned
together. Re-running on the same commit range reproduces the dataset exactly.
8. Validation
The detector was validated against a synthetic repository constructed to exercise every kind
(a 10-commit history with one move engineered per phenomenon). Result under --sample=all,
core lexicon:
- All eight headline kinds fired, 20 events total.
- The priority rule behaved as specified: a move from
misc/todocs/guide/was labeledde_residualization(most specific) while recordingdepth_delta = +1. residual_loadread 0% for three snapshots, 25% at the snapshot where a file was parked inmisc/, then 0% again once it was rehomed. The transient spike is precisely the torque an endpoint-only analysis would not see, and is the empirical signature the design exists to capture.
9. Suggested analyses (paper directions)
The dataset (events.csv, metrics.csv, and the snapshot rows) supports, among others:
- Regrading rate over time. Is reclassification continuous, or does it cluster into campaigns? Do campaigns coincide with feature work or follow it (debt repayment)?
- Residual dynamics. Does residual load accrete monotonically (entropy) or get
periodically cleaned (de-residualization campaigns)? What is the half-life of a file in
misc? - Breadth versus depth. Does the scheme deepen or widen as it grows, and when does it reorganize from one to the other?
- Cross-repository comparison. Run the identical, parameter-logged pipeline across several repositories and compare regrading signatures. This is where a single case study becomes a finding.
The point throughout: a versioned repository lets classification theory be tested against a fully dated record of a scheme's own history, which is uncommon, and the measurements above are the bridge between the theory and that record.