Map classification coverage and scope authority projection research

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0cffe-206f-7323-89d3-b20ca4cf4bf9
This commit is contained in:
tegwick 2026-09-27 01:49:50 +02:00
parent 9ac6f6925b
commit b2f50aa3f3
8 changed files with 674 additions and 0 deletions

View file

@ -19,3 +19,10 @@ evolution-check:
evolution-test:
PYTHONDONTWRITEBYTECODE=1 "$(BENCH_PY)" -m pytest -q -p no:cacheprovider tests/test_research_evolution.py
.PHONY: classification-report classification-check
classification-report:
python3 scripts/classification_coverage.py
classification-check:
python3 scripts/classification_coverage.py --check

View file

@ -261,6 +261,8 @@ research/candidates/VersionCheckedMutation.md
research/candidates/VerticalFeatureSlice.md
research/cases/CarniatoGrandUnifyingArchitecture.md
research/cases/LocalFirstAuthority.md
research/catalog/ClassificationCoverage.json
research/catalog/ClassificationCoverage.md
research/catalog/PatternCandidateCatalog.md
research/catalog/SourceCatalog.md
research/compendium/FrontendArchitectureCompendium.md
@ -422,6 +424,7 @@ research/experiments/navigation-history/ownership.mjs
research/experiments/navigation-history/package-lock.json
research/experiments/navigation-history/package.json
research/experiments/navigation-history/result.json
research/plan/AuthorityProjectionComparison.md
research/plan/OpenQuestions.md
research/plan/ResearchProgram.md
research/plan/ResearchProtocol.md
@ -474,6 +477,7 @@ research/walkthroughs/VC01-TransactionalAdministration.md
research/walkthroughs/VC02-OfflineFieldNotes.md
research/walkthroughs/VC03-ContentPublication.md
research/walkthroughs/VC06-MicrofrontendEstate.md
scripts/classification_coverage.py
scripts/research_admission.py
scripts/research_bench.py
scripts/research_evolution.py

View file

@ -0,0 +1,330 @@
{
"schema_version": 1,
"assessed_at": "2026-09-27",
"assessor": "Codex",
"status": "provisional author-model classification",
"basis_revision": "9ac6f6925be6743113338ad140f8465b2d99a404",
"counting_rule": "Count a candidate once per assigned label; labels overlap. Responsibilities describe the direct mechanism, not every prerequisite or downstream effect. Forces are selected trade-offs, not exhaustive coverage or measured outcomes.",
"candidates": [
{
"path": "research/candidates/ConflictCopy.md",
"sha256": "24f250d89ac17d96df287d67c275b5320b48c8356b57ae126a6c941e92a1c6e9",
"title": "Conflict Copy",
"responsibilities": [
"reconciliation"
],
"forces": {
"improves": [
"recoverability",
"information-completeness"
],
"worsens": [
"cognitive-load",
"reconciliation-complexity"
]
},
"rationale": "Preserves divergent content for later semantic resolution; unresolved copies impose review and merge work."
},
{
"path": "research/candidates/DerivedState.md",
"sha256": "9f29b9f1296a52b83f08dfd97437c4dc16e4949ddac1ff3b3830e3fc9831bd4f",
"title": "Derived State",
"responsibilities": [
"projection"
],
"forces": {
"improves": [
"authoritative-consistency"
],
"worsens": [
"client-compute-cost",
"cache-invalidation-complexity"
]
},
"rationale": "Projects coherent inputs without separately mutable derived copies; recomputation and cached dependency tracking cost work."
},
{
"path": "research/candidates/ExplicitReconciliation.md",
"sha256": "d48a40aab7417b8b8f8406094c84b9e90d0ca8c2f94d6e616d0b80499dc04959",
"title": "Explicit Reconciliation",
"responsibilities": [
"reconciliation",
"affordance"
],
"forces": {
"improves": [
"information-completeness",
"recoverability"
],
"worsens": [
"cognitive-load",
"continuity-of-interaction"
]
},
"rationale": "Makes semantic resolution an explicit comparison task; deciding among versions interrupts ordinary work."
},
{
"path": "research/candidates/FailureBoundary.md",
"sha256": "a6e76ed17a92baade683d5df96fa8ecd066c593661e6a14983a86d046e7d9c2c",
"title": "Failure Boundary",
"responsibilities": [
"composition",
"affordance"
],
"forces": {
"improves": [
"fault-containment",
"continuity-of-interaction"
],
"worsens": [
"implementation-complexity"
]
},
"rationale": "Contains declared failures and supplies recovery interaction; partial-state recovery and escalation add complexity."
},
{
"path": "research/candidates/FocusReturn.md",
"sha256": "9149c2f563eafcfec983a9285949225840d97804568309bd16bbb1eb6b3dde77",
"title": "Focus Return",
"responsibilities": [
"affordance"
],
"forces": {
"improves": [
"continuity-of-interaction",
"accessibility"
],
"worsens": [
"implementation-complexity"
]
},
"rationale": "Restores a meaningful keyboard continuation; disappearing targets and nested ownership require lifecycle handling."
},
{
"path": "research/candidates/IndependentFeatureBoundary.md",
"sha256": "60b78725ed4036681675d4c68244fc25aea6e0dffb09d54a7108e3fcbf527b4f",
"title": "Independent Feature Boundary",
"responsibilities": [
"composition",
"execution"
],
"forces": {
"improves": [
"independent-deployability",
"team-autonomy"
],
"worsens": [
"compatibility-pressure",
"deployment-complexity"
]
},
"rationale": "Separates release and activation through composition contracts; version compatibility and session transitions add obligations."
},
{
"path": "research/candidates/InvalidateAndReproject.md",
"sha256": "47c405adbc3caac2383768ed3d30b6a2e7ff1f44f4954c340049e78944227844",
"title": "Invalidate and Reproject",
"responsibilities": [
"synchronization",
"projection"
],
"forces": {
"improves": [
"freshness"
],
"worsens": [
"bandwidth-cost",
"cache-invalidation-complexity"
]
},
"rationale": "Refreshes affected observations after accepted writes; scope and ordering of network/cache work need explicit management."
},
{
"path": "research/candidates/IslandsOfInteractivity.md",
"sha256": "821a1497da10c02ae11fa6f56cb8e205a4f32c40b39770ab8ca3f907561a260a",
"title": "Islands of Interactivity",
"responsibilities": [
"projection",
"execution"
],
"forces": {
"improves": [
"client-compute-cost"
],
"worsens": [
"implementation-complexity"
]
},
"rationale": "Scopes activation to selected regions; intended compute savings compete with loading and inter-region coordination. Savings require measurement."
},
{
"path": "research/candidates/LocalCommitBoundary.md",
"sha256": "22165fc2979e8f4d8859b34417cb71e7b5ec7a8440ad045aee2383d499648013",
"title": "Local Commit Boundary",
"responsibilities": [
"authority",
"mutation"
],
"forces": {
"improves": [
"recoverability",
"offline-usability"
],
"worsens": [
"implementation-complexity",
"perceived-responsiveness"
]
},
"rationale": "Defines acknowledged local acceptance separately from visual input; atomic persistence and waiting for completion add cost."
},
{
"path": "research/candidates/LocalDraftState.md",
"sha256": "8e5f427975c76083c80b895bc68b7130b249be5129c2854f3df11cc374b4b240",
"title": "Local Draft State",
"responsibilities": [
"affordance",
"mutation"
],
"forces": {
"improves": [
"recoverability",
"continuity-of-interaction"
],
"worsens": [
"implementation-complexity",
"privacy"
]
},
"rationale": "Preserves editable intent separately from refreshed observations; lifetime management adds complexity and sensitive-data retention risk."
},
{
"path": "research/candidates/MutationOutcomeTracking.md",
"sha256": "e04cb835fd054bfaf88616375bd0262deffb2801ea04105be92543bfa9582179",
"title": "Mutation Outcome Tracking",
"responsibilities": [
"mutation",
"reconciliation"
],
"forces": {
"improves": [
"recoverability",
"information-completeness"
],
"worsens": [
"implementation-complexity"
]
},
"rationale": "Tracks uncertain write outcomes and resolves them through receipt lookup or bounded replay; identity/retention state adds cost."
},
{
"path": "research/candidates/PendingSynchronization.md",
"sha256": "9c5cb0f4ea4e6f4406ce55513ca2c252172427a49d8280ae1a9c713f1d11b070",
"title": "Pending Synchronization",
"responsibilities": [
"synchronization"
],
"forces": {
"improves": [
"offline-usability",
"recoverability"
],
"worsens": [
"freshness",
"reconciliation-complexity"
]
},
"rationale": "Keeps locally accepted work queued across disconnection; remote freshness is delayed and retry/reconciliation contracts are required."
},
{
"path": "research/candidates/PresentationModel.md",
"sha256": "5ff03b5799b0a9e5ec6b54b21034720d89dbc8ffde7c4cdcf71616cdf57baf49",
"title": "Presentation Model",
"responsibilities": [
"projection",
"affordance"
],
"forces": {
"improves": [
"testability",
"portability"
],
"worsens": [
"implementation-complexity"
]
},
"rationale": "Separates presentation decisions from widget APIs; model/view binding and synchronization add a failure surface."
},
{
"path": "research/candidates/ProgressiveEnhancement.md",
"sha256": "1dc3885ef896b9a7cb61af11fa8893484eb1e13454207326abc7250d5ca4382b",
"title": "Progressive Enhancement",
"responsibilities": [
"execution",
"affordance"
],
"forces": {
"improves": [
"recoverability"
],
"worsens": [
"implementation-complexity"
]
},
"rationale": "Preserves an essential baseline when optional scripts fail; equivalent task semantics and recovery across paths add design work."
},
{
"path": "research/candidates/URLAddressableState.md",
"sha256": "07d524c3c0dd080bd42ff5dd79a36e6ecd2a8654f07ece880b483477f7ca4497",
"title": "URL-addressable State",
"responsibilities": [
"address"
],
"forces": {
"improves": [
"addressability"
],
"worsens": [
"privacy",
"compatibility-pressure"
]
},
"rationale": "Makes selected views reconstructible from addresses; exposure and evolving URL contracts constrain what can be encoded."
},
{
"path": "research/candidates/VersionCheckedMutation.md",
"sha256": "6a3335ae2fa1de51c95dcbfa8d766d988a3f7a9604fb608b8a0bcf9a10b64198",
"title": "Version-Checked Mutation",
"responsibilities": [
"authority",
"mutation",
"reconciliation"
],
"forces": {
"improves": [
"authoritative-consistency"
],
"worsens": [
"cognitive-load"
]
},
"rationale": "Checks stale bases at commit and exposes rejected proposals for reconsideration; contention adds repeated user review."
},
{
"path": "research/candidates/VerticalFeatureSlice.md",
"sha256": "d6b332b9c104a079bd4b72512b8ddd1a889199b2e2e531753c411688053e647a",
"title": "Vertical Feature Slice",
"responsibilities": [
"composition"
],
"forces": {
"improves": [
"feature-change-frequency"
],
"worsens": [
"implementation-complexity"
]
},
"rationale": "Localizes a capability change behind an interface; shared concepts and interfaces require maintenance. Benefit means coping with frequent changes, not changing their frequency."
}
]
}

View file

@ -0,0 +1,147 @@
# Classification coverage
Generated by `python3 scripts/classification_coverage.py`; assessment: 2026-09-27.
17 developed drafts; 16 original seeds at `2a5dabd`. 7 original seeds developed, 9 without dedicated drafts, 10 later additions. All current candidates remain hypotheses; classification confers no admission or new evidence.
Families/scales come from current candidate metadata. Responsibilities and forces are provisional author-model interpretations in [ClassificationCoverage.json](ClassificationCoverage.json), with candidate hashes and per-record rationale. They are separate from canonical metadata.
Count a candidate once per assigned label; labels overlap. Responsibilities describe the direct mechanism, not every prerequisite or downstream effect. Forces are selected trade-offs, not exhaustive coverage or measured outcomes.
A zero means no assigned direct coverage, not absence of discussion. Force direction describes an intended favorable effect or accepted cost, not a measured result. A classification refresh requires reading changed candidates; do not merely replace hashes.
## Families
| Family | Original seeds | Developed drafts |
| --- | ---: | ---: |
| authority | 3 | 2 |
| address | 1 | 1 |
| projection | 4 | 4 |
| affordance | 2 | 6 |
| mutation | 0 | 4 |
| synchronization | 2 | 5 |
| composition | 2 | 4 |
| execution | 0 | 3 |
| quality | 2 | 3 |
## Scales
| Scale | Original seeds | Developed drafts |
| --- | ---: | ---: |
| L0 | 0 | 0 |
| L1 | 0 | 1 |
| L2 | 3 | 6 |
| L3 | 7 | 5 |
| L4 | 2 | 3 |
| L5 | 1 | 2 |
| L6 | 4 | 13 |
| L7 | 0 | 0 |
| cross-scale | 1 | 0 |
## Responsibilities
These are direct-mechanism assignments, not family aliases. In particular, reconciliation is a responsibility and quality is a family.
| Responsibility | Drafts |
| --- | ---: |
| address | 1 |
| authority | 2 |
| projection | 4 |
| affordance | 6 |
| mutation | 4 |
| synchronization | 2 |
| reconciliation | 4 |
| composition | 3 |
| execution | 3 |
## Forces
Selected trade-offs only. Counts are unique candidates per force, even if a force appears on both sides. Unassigned forces remain research questions; the mapping does not certify a benefit.
| Force | Intended benefit | Cost / tension | Distinct drafts |
| --- | ---: | ---: | ---: |
| interaction-latency | 0 | 0 | 0 |
| perceived-responsiveness | 0 | 1 | 1 |
| continuity-of-interaction | 3 | 1 | 4 |
| discoverability | 0 | 0 | 0 |
| addressability | 1 | 0 | 1 |
| accessibility | 1 | 0 | 1 |
| recoverability | 7 | 0 | 7 |
| offline-usability | 2 | 0 | 2 |
| authoritative-consistency | 2 | 0 | 2 |
| freshness | 1 | 1 | 2 |
| cacheability | 0 | 0 | 0 |
| conflict-probability | 0 | 0 | 0 |
| collaborative-concurrency | 0 | 0 | 0 |
| data-locality | 0 | 0 | 0 |
| privacy | 0 | 2 | 2 |
| information-completeness | 3 | 0 | 3 |
| first-content-latency | 0 | 0 | 0 |
| hydration-cost | 0 | 0 | 0 |
| client-compute-cost | 1 | 1 | 2 |
| server-compute-cost | 0 | 0 | 0 |
| bandwidth-cost | 0 | 1 | 1 |
| connection-lifetime | 0 | 0 | 0 |
| network-reliability | 0 | 0 | 0 |
| startup-cost | 0 | 0 | 0 |
| incremental-update-cost | 0 | 0 | 0 |
| feature-change-frequency | 1 | 0 | 1 |
| schema-change-frequency | 0 | 0 | 0 |
| independent-deployability | 1 | 0 | 1 |
| team-autonomy | 1 | 0 | 1 |
| release-coupling | 0 | 0 | 0 |
| compatibility-pressure | 0 | 2 | 2 |
| implementation-complexity | 0 | 9 | 9 |
| reconciliation-complexity | 0 | 2 | 2 |
| cognitive-load | 0 | 3 | 3 |
| testability | 1 | 0 | 1 |
| observability | 0 | 0 | 0 |
| debuggability | 0 | 0 | 0 |
| portability | 1 | 0 | 1 |
| security-exposure | 0 | 0 | 0 |
| scalability | 0 | 0 | 0 |
| fault-containment | 1 | 0 | 1 |
| deployment-complexity | 0 | 1 | 1 |
| cache-invalidation-complexity | 0 | 2 | 2 |
| telemetry-quality | 0 | 0 | 0 |
| incident-recoverability | 0 | 0 | 0 |
## Per-candidate responsibility and force rationale
| Candidate | Responsibilities | Intended benefit | Cost / tension | Rationale |
| --- | --- | --- | --- | --- |
| [Conflict Copy](../candidates/ConflictCopy.md) | reconciliation | recoverability, information-completeness | cognitive-load, reconciliation-complexity | Preserves divergent content for later semantic resolution; unresolved copies impose review and merge work. |
| [Derived State](../candidates/DerivedState.md) | projection | authoritative-consistency | client-compute-cost, cache-invalidation-complexity | Projects coherent inputs without separately mutable derived copies; recomputation and cached dependency tracking cost work. |
| [Explicit Reconciliation](../candidates/ExplicitReconciliation.md) | reconciliation, affordance | information-completeness, recoverability | cognitive-load, continuity-of-interaction | Makes semantic resolution an explicit comparison task; deciding among versions interrupts ordinary work. |
| [Failure Boundary](../candidates/FailureBoundary.md) | composition, affordance | fault-containment, continuity-of-interaction | implementation-complexity | Contains declared failures and supplies recovery interaction; partial-state recovery and escalation add complexity. |
| [Focus Return](../candidates/FocusReturn.md) | affordance | continuity-of-interaction, accessibility | implementation-complexity | Restores a meaningful keyboard continuation; disappearing targets and nested ownership require lifecycle handling. |
| [Independent Feature Boundary](../candidates/IndependentFeatureBoundary.md) | composition, execution | independent-deployability, team-autonomy | compatibility-pressure, deployment-complexity | Separates release and activation through composition contracts; version compatibility and session transitions add obligations. |
| [Invalidate and Reproject](../candidates/InvalidateAndReproject.md) | synchronization, projection | freshness | bandwidth-cost, cache-invalidation-complexity | Refreshes affected observations after accepted writes; scope and ordering of network/cache work need explicit management. |
| [Islands of Interactivity](../candidates/IslandsOfInteractivity.md) | projection, execution | client-compute-cost | implementation-complexity | Scopes activation to selected regions; intended compute savings compete with loading and inter-region coordination. Savings require measurement. |
| [Local Commit Boundary](../candidates/LocalCommitBoundary.md) | authority, mutation | recoverability, offline-usability | implementation-complexity, perceived-responsiveness | Defines acknowledged local acceptance separately from visual input; atomic persistence and waiting for completion add cost. |
| [Local Draft State](../candidates/LocalDraftState.md) | affordance, mutation | recoverability, continuity-of-interaction | implementation-complexity, privacy | Preserves editable intent separately from refreshed observations; lifetime management adds complexity and sensitive-data retention risk. |
| [Mutation Outcome Tracking](../candidates/MutationOutcomeTracking.md) | mutation, reconciliation | recoverability, information-completeness | implementation-complexity | Tracks uncertain write outcomes and resolves them through receipt lookup or bounded replay; identity/retention state adds cost. |
| [Pending Synchronization](../candidates/PendingSynchronization.md) | synchronization | offline-usability, recoverability | freshness, reconciliation-complexity | Keeps locally accepted work queued across disconnection; remote freshness is delayed and retry/reconciliation contracts are required. |
| [Presentation Model](../candidates/PresentationModel.md) | projection, affordance | testability, portability | implementation-complexity | Separates presentation decisions from widget APIs; model/view binding and synchronization add a failure surface. |
| [Progressive Enhancement](../candidates/ProgressiveEnhancement.md) | execution, affordance | recoverability | implementation-complexity | Preserves an essential baseline when optional scripts fail; equivalent task semantics and recovery across paths add design work. |
| [URL-addressable State](../candidates/URLAddressableState.md) | address | addressability | privacy, compatibility-pressure | Makes selected views reconstructible from addresses; exposure and evolving URL contracts constrain what can be encoded. |
| [Version-Checked Mutation](../candidates/VersionCheckedMutation.md) | authority, mutation, reconciliation | authoritative-consistency | cognitive-load | Checks stale bases at commit and exposes rejected proposals for reconsideration; contention adds repeated user review. |
| [Vertical Feature Slice](../candidates/VerticalFeatureSlice.md) | composition | feature-change-frequency | implementation-complexity | Localizes a capability change behind an interface; shared concepts and interfaces require maintenance. Benefit means coping with frequent changes, not changing their frequency. |
## Original seeds without dedicated drafts
- Server Authority
- Local Authority
- Replicated Authority
- Server Projection
- Client Projection
- Streaming Projection
- Local Interaction State
- Optimistic Overlay
- Persistent Subscription
## Research implication
The developed corpus concentrates on interaction/recovery; authority placement and basic projection choices remain underdeveloped. Family membership alone hides this gap. The next bounded authority/projection comparison is specified in [the research brief](../plan/AuthorityProjectionComparison.md). Keep the navigation fixture paused; pending Zulip applicability questions remain in WP-0003 T01.
This inventory is a coverage aid, not a maturity score, empirical learning cycle, graph export or proof that the initial ontology is sufficient.

View file

@ -2,6 +2,10 @@
This file tracks concepts before promotion into canonical pattern files.
See [ClassificationCoverage.md](ClassificationCoverage.md) for current counts by
family, scale, responsibility and force, and the comparison against the initial
sixteen seeds. Responsibility/force assignments are provisional editorial mappings.
| Candidate | Family | Scale | Status | Main force |
|---|---|---:|---|---|
| Server Authority | authority | L2 | seed | authoritative consistency |

View file

@ -0,0 +1,62 @@
# Next bounded comparison — authority placement and projection
Prepared: 2026-09-27 · WP-0003 T01 · Status: ready for prospective registration.
This brief selects the next breadth investigation; no source investigation or
empirical cycle has been executed by writing it.
## Why this question
The [classification inventory](../catalog/ClassificationCoverage.md) finds that
seven of the original sixteen seeds have developed drafts. None of Server Authority,
Local Authority, Replicated Authority, Server Projection, Client Projection or
Streaming Projection has a dedicated developed draft. Current authority-family
membership instead describes acceptance/precondition mechanisms. The language needs
to explain placement decisions as well as recovery after those decisions.
Do these six seed names describe reusable patterns, context choices, implementation
strategies or delivery mechanisms? Which independent decisions are conflated when
we pair server authority with server rendering, or local authority with client rendering?
## Bounded method
1. Register one prospective cycle before new evidence collection, with a new
comparison group for this documentary/conceptual protocol. Record effort and
source access limits; do not pool it with navigation runtime cycles.
2. Reuse existing Carniato/local-first and navigation/rendering reviews as prior
interpretations, not new independent evidence. Inspect at most six primary-source
documents across at least two independent source families. Pin versions or record
access dates and claim locators. Sources may corroborate only parts of a contract.
3. For each of the six seeds, describe the relevant authority scope, acceptance
boundary, replica/cache semantics, projection inputs, execution location and
delivery timing. Keep optimistic display distinct from accepted authority and
streaming delivery distinct from where projection is computed.
4. Construct a decision matrix for two synthetic briefs already represented by
VC-01 transactional administration and VC-02 offline field notes. Vary projection
placement while holding authority assumptions explicit. State incompatible or
unsupported combinations rather than invent implementations. These are conceptual
probes, not new validated walkthroughs or deployed known uses.
5. Record a disposition for each seed: develop a candidate, retain as a seed, treat
as context/strategy, merge, or reject—with evidence and unresolved questions.
Produce at most two new drafts, and only where context, competing forces,
consequences and alternatives justify distinct patterns. Zero is a valid result.
## Acceptance, limits and handoff
Deliver a claim table, the two decision traces and six seed dispositions. Identify
at least one conflation or counterexample, or explicitly report that none was located
in the bounded evidence. Review responsibility/force mappings against resulting
candidate changes, then regenerate coverage and update evolution profiles/ledger at
the normal review boundary. No automatic canonical promotion or gate closure.
Stop after six primary documents or 45 active research minutes, whichever occurs
first; allow up to 10 additional verification minutes. Register these limits with the
cycle before starting. Preserve unknowns instead of widening silently. Live inference,
if needed later, uses llm-connect; this brief requires no model calls or new runtime
fixture. It does not establish measured performance, production guarantees or human
usefulness.
WP-0003 T01 retains the bounded Zulip caller/transport/test follow-up as an unresolved
navigation applicability question. Broadening does not require declaring that question
resolved; preserve its limitations and keep the authored navigation fixture paused.
WP-0002 T03 retains independent seed/usefulness review. M1/M2 and WP-0004 prerequisites
remain unchanged. Classification is a research aid, not a demand to fill every cell.

View file

@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""Render a provisional coverage inventory; refuse stale or invalid mappings."""
import argparse
from collections import Counter
import hashlib
import json
from pathlib import Path
import re
import subprocess
ROOT = Path(__file__).resolve().parents[1]
MAPPING = ROOT / 'research/catalog/ClassificationCoverage.json'
REPORT = ROOT / 'research/catalog/ClassificationCoverage.md'
INITIAL = '2a5dabd'
RESPONSIBILITIES = 'address authority projection affordance mutation synchronization reconciliation composition execution'.split()
def section_values(text, key):
section = re.search(r'^' + re.escape(key) + r':\n((?:- [^\n]+\n)+)', text, re.M)
if section is None:
raise ValueError('Missing vocabulary section: ' + key)
return re.findall(r'^- ([\w-]+)$', section[1], re.M)
def render():
data = json.loads(MAPPING.read_text())
vocab = (ROOT / 'canon/vocabulary.yaml').read_text()
families = section_values(vocab, 'families')
scales = section_values(vocab, 'scales')
forces = section_values(vocab, 'forces')
records = data['candidates']
paths = [r['path'] for r in records]
actual = {str(p.relative_to(ROOT)) for p in (ROOT / 'research/candidates').glob('*.md')}
if len(set(paths)) != len(paths) or set(paths) != actual:
raise ValueError('Classification must cover every candidate exactly once')
counts = {k: Counter() for k in ['families', 'scales', 'responsibilities', 'improves', 'worsens']}
for r in records:
raw = (ROOT / r['path']).read_bytes()
if hashlib.sha256(raw).hexdigest() != r['sha256']:
raise ValueError('Review classification after candidate changed: ' + r['path'])
front = raw.decode().split('---')[1]
if re.search(r'^title: (.*)$', front, re.M)[1] != r['title'] or not r['rationale'].strip():
raise ValueError('Invalid title/rationale: ' + r['path'])
for key, allowed in [('families', families), ('scales', scales)]:
labels = [s.strip() for s in re.search(r'^' + key + r': \[(.*)\]$', front, re.M)[1].split(',')]
if len(labels) != len(set(labels)) or not set(labels) <= set(allowed):
raise ValueError('Invalid ' + key)
counts[key].update(labels)
for key, labels, allowed in [('responsibilities', r['responsibilities'], RESPONSIBILITIES),
('improves', r['forces']['improves'], forces),
('worsens', r['forces']['worsens'], forces)]:
if not labels or len(labels) != len(set(labels)) or not set(labels) <= set(allowed):
raise ValueError('Invalid classification ' + key + ': ' + r['path'])
counts[key].update(labels)
initial = subprocess.check_output(['git', 'show', INITIAL + ':research/catalog/PatternCandidateCatalog.md'], cwd=ROOT, text=True)
seed_rows = [[c.strip() for c in line.strip('|').split('|')] for line in initial.splitlines() if '| seed |' in line]
original_family = Counter(r[1] for r in seed_rows)
original_scale = Counter(s for r in seed_rows for s in r[2].split('/'))
developed = {r['title'].casefold() for r in records}
aliases = {'URL as Application State': 'URL-addressable State'}
covered = [r[0] for r in seed_rows if aliases.get(r[0], r[0]).casefold() in developed]
uncovered = [r[0] for r in seed_rows if r[0] not in covered]
lines = ['# Classification coverage', '', 'Generated by `python3 scripts/classification_coverage.py`; assessment: ' + data['assessed_at'] + '.', '',
f"{len(records)} developed drafts; {len(seed_rows)} original seeds at `{INITIAL}`. {len(covered)} original seeds developed, {len(uncovered)} without dedicated drafts, {len(records)-len(covered)} later additions. All current candidates remain hypotheses; classification confers no admission or new evidence.", '',
'Families/scales come from current candidate metadata. Responsibilities and forces are provisional author-model interpretations in [ClassificationCoverage.json](ClassificationCoverage.json), with candidate hashes and per-record rationale. They are separate from canonical metadata.', '',
data['counting_rule'], '', 'A zero means no assigned direct coverage, not absence of discussion. Force direction describes an intended favorable effect or accepted cost, not a measured result. A classification refresh requires reading changed candidates; do not merely replace hashes.', '',
'## Families', '', '| Family | Original seeds | Developed drafts |', '| --- | ---: | ---: |']
lines += [f'| {k} | {original_family[k]} | {counts["families"][k]} |' for k in families]
lines += ['', '## Scales', '', '| Scale | Original seeds | Developed drafts |', '| --- | ---: | ---: |']
lines += [f'| {k} | {original_scale[k]} | {counts["scales"][k]} |' for k in scales + ['cross-scale']]
lines += ['', '## Responsibilities', '', 'These are direct-mechanism assignments, not family aliases. In particular, reconciliation is a responsibility and quality is a family.', '', '| Responsibility | Drafts |', '| --- | ---: |']
lines += [f'| {k} | {counts["responsibilities"][k]} |' for k in RESPONSIBILITIES]
lines += ['', '## Forces', '', 'Selected trade-offs only. Counts are unique candidates per force, even if a force appears on both sides. Unassigned forces remain research questions; the mapping does not certify a benefit.', '', '| Force | Intended benefit | Cost / tension | Distinct drafts |', '| --- | ---: | ---: | ---: |']
for k in forces:
n = sum(k in r['forces']['improves'] or k in r['forces']['worsens'] for r in records)
lines.append(f'| {k} | {counts["improves"][k]} | {counts["worsens"][k]} | {n} |')
lines += ['', '## Per-candidate responsibility and force rationale', '', '| Candidate | Responsibilities | Intended benefit | Cost / tension | Rationale |', '| --- | --- | --- | --- | --- |']
for r in records:
lines.append('| [' + r['title'] + '](' + '../candidates/' + Path(r['path']).name + ') | ' + ', '.join(r['responsibilities']) + ' | ' + ', '.join(r['forces']['improves']) + ' | ' + ', '.join(r['forces']['worsens']) + ' | ' + r['rationale'] + ' |')
lines += ['', '## Original seeds without dedicated drafts', '']
lines += ['- ' + s for s in uncovered]
lines += ['', '## Research implication', '',
'The developed corpus concentrates on interaction/recovery; authority placement and basic projection choices remain underdeveloped. Family membership alone hides this gap. The next bounded authority/projection comparison is specified in [the research brief](../plan/AuthorityProjectionComparison.md). Keep the navigation fixture paused; pending Zulip applicability questions remain in WP-0003 T01.', '',
'This inventory is a coverage aid, not a maturity score, empirical learning cycle, graph export or proof that the initial ontology is sufficient.', '']
return '\n'.join(lines)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--check', action='store_true')
args = parser.parse_args()
content = render()
if args.check:
if not REPORT.exists() or REPORT.read_text() != content:
raise SystemExit('Classification report is stale; review mappings and regenerate')
print('Candidate coverage, hashes, vocabulary and generated report are consistent.')
else:
REPORT.write_text(content)
print('Wrote ' + str(REPORT.relative_to(ROOT)))
if __name__ == '__main__':
main()

View file

@ -251,3 +251,20 @@ defect. T02 retains independent human/AT and offline-case obligations. WP-0006 T
retains remaining review dates and comparable-window work; this static protocol is
not pooled with runtime cycles. No M1/M2 closure. See
research/reviews/ZulipNavigationSourceStudy.md and ZulipNavigationSources.json.
## Systematic classification and next breadth slice — 2026-09-27
T01: ClassificationCoverage.json records provisional direct-responsibility and
selected force trade-offs for all seventeen candidate drafts, with hashes and
rationales. ClassificationCoverage.md is generated and checked against current
candidate families/scales and the original sixteen-seed inventory. Seven original
seeds have developed drafts; nine lack dedicated drafts. No new pattern or evidence
promotion; assignments are author-model interpretations, not full-schema admission.
The next breadth slice is [AuthorityProjectionComparison](../research/plan/AuthorityProjectionComparison.md):
preregister a bounded six-seed authority/projection comparison, distinguish context
choices from patterns, and produce at most two justified drafts. Registration and
execution remain pending; zero new drafts is a valid outcome. The earlier Zulip
caller/transport/test question remains open with its recorded limitations; no fixture
restart. WP-0002 T03 independent validation, T02/T03 gates here, and WP-0006 comparable
measurement remain unchanged. Do not treat classification counts as maturity.