Complexity measurements for analyst jobs
Commissioned by the operator on 2026-10-03 to decide between shortening the
kb/agentic-systems/ contract and splitting analyses into
kb/agentic-system-analyses/. Agent-measured. These are judgments under the
rules in Counting rules; every item behind a count is listed
in complexity-measurements.json. No run,
model call or workflow step was made.
Result
The split has a measured complexity advantage over shortening for every analyst role, but only on one measure, Concerns. Shortening reaches the same Model-resolved reference counts. On Authority conflicts it falls short of the split by one conflict per role. That conflict exists only if a permissive link grammar counts as a conflict.
Primary roles, "incumbent / shortening / split". Incumbent means the current contract as deployed: root doctrine requires it and packets omit it.
| Role | Concerns | Model-resolved references | Authority conflicts |
|---|---|---|---|
| boundary | 10 / 9 / 4 | 1 / 0 / 0 | 4 / 1 / 0 |
| runtime | 10 / 9 / 3 | 9 / 4 / 4 | 3 / 1 / 0 |
| memory | 10 / 9 / 3 | 9 / 4 / 4 | 4 / 2 / 1 |
| epistemic | 10 / 9 / 3 | 9 / 4 / 4 | 3 / 1 / 0 |
Secondary roles, same order:
| Role | Concerns | Model-resolved references | Authority conflicts |
|---|---|---|---|
| reconcile | 10 / 9 / 3 | 5 / 4 / 4 | 5 / 2 / 1 |
| verify | 10 / 9 / 3 | 6 / 5 / 5 | 4 / 1 / 0 |
| synthesize | 10 / 9 / 5 | 11 / 6 / 6 | 4 / 1 / 0 |
| verify-synthesis | 10 / 9 / 5 | 6 / 5 / 5 | 4 / 1 / 0 |
What these counts establish:
- Concerns. Shortening removes one activity of ten, note authoring. The split removes five to seven. Neither reaches the proposal's target of zero. The split keeps three activities from its own contract: method authoring for local types, retained and archive maintenance, and run-state conventions. Role files add one or two more that no contract change can remove. The boundary job reads publication metadata. The records contract has an archive clause. The overview type has publication and comparison-row rules.
- Model-resolved references. Shortening equals the split for every role. Both remove the same references: the contract lookup (packet entry) and four incumbent link and search instructions. Four to six references remain under both. They come from the root vocabulary rule and the shared records contract, not from any collection contract. They are the largest remaining source of references.
- Authority conflicts. Both candidates remove the root-rule conflict and the
incumbent's evidence-line and note-promotion conflicts. Shortening keeps
one conflict, CF-PRIOR. Its link grammar admits related accounts in
kb/agent-memory-systems/and retained analyses, and the worker rules forbid reading them. The grammar permits these links and does not require them. If permissive grammar is not counted, shortening equals the split on conflicts. Two conflicts are the same under both candidates: memory's blocked-report rule against the worker rules, and reconciliation's set-directory link rule. - Packet entry alone (Sol plan item 1 with the full incumbent contract) removes one reference and one conflict per role. It leaves all ten concerns. Primary roles go to 10 concerns, 0 or 8 references, and 2 or 3 conflicts.
Remaining complexity is in the task, not in the contract. The two task-intrinsic measures are the same in shortening and the split.
| Role | Output obligations (incumbent / candidates) | Flagged publication or comparison only | Max composition depth (incumbent / candidates where different) | Obligations above depth two (incumbent / candidates) |
|---|---|---|---|---|
| boundary | 16 / 15 | 0 | 4 | 5 / 4 |
| runtime | 41 / 39 | 0 | 3 | 5 / 2 |
| memory | 62 / 60 | 14 | 4 | 10 / 7 |
| epistemic | 51 / 49 | 0 | 4 | 5 / 2 |
| reconcile | 20 / 19 | 2 | 5 | 7 / 7 |
| verify | 14 / 13 | 1 | 4 | 3 / 3 |
| synthesize | 18 / 16 | 2 | 5 / 4 | 4 / 3 |
| verify-synthesis | 11 / 10 | 1 | 5 | 1 / 1 |
The three largest task-intrinsic findings, with uncertainty:
- The memory comparison profile is a quarter of the memory job's
obligations, and only comparison consumes it. 14 of 60 memory
obligations serve only cross-system comparison. They are the profile's
scope, its ten axes, the axis field structure, scope agreement and
Comparison rationale. No synthesis or overview rule reads the profile.
Its consumers are
systems_matrix.py, landscape synthesis and taxonomy refresh. The profile check is reconciliation's deepest obligation (five files) and one of verification's three deepest. In the records, three of the four findings returned to a memory analyst concern profile obligations: two in Dynamic Cheatsheet run -02 and one in Graphiti. Moving the profile to a coordinator or comparison step is the largest available reduction. That is a method change; the proposal does not decide it. - Record grammar is restated across files, and its lexical rules are the most frequent observed lapse. Reconciliation has seven obligations above depth two. Amendment, supersession, split, part and unresolved-conflict rules each appear in the records contract, the reconciliation type and the job file. The no-range rule appears once, in the 13.7 KB records contract. Only the two verification job files restate it. Range lapses occurred in the epistemic job (both Dynamic Cheatsheet runs), in verify jobs before restatement, and in reconcile and synthesize after it. These lapses have depth one or two. I infer that salience at the point of writing explains them better than composition depth. Two runs on one source cannot test that inference.
- Theory and boundary obligations need files the packet does not supply.
The four registered definitions in the records contract are required by
root doctrine and absent from every packet. Synthesis also needs
self-improving-system.md, and verify needs boundary-kind semantics from the boundary contract. The one synthesis blocker in run -02 was a missing self-improvement assessment. That obligation needsD:SI, which the synthesizer must look up itself. The boundary's not-allowlist rule has depth four. The same rule is stated in the job, the boundary contract, the sources contract and the worker rules. The register-fidelity defect that survived run -02 concerns this obligation.
Measured versus inferred: all counts are measured under the stated rules. The links between counts and observed failures are matches by obligation, not causal attributions. No run loaded either candidate contract. In the two Dynamic Cheatsheet runs no worker read the incumbent, so no record shows the contract's content causing an analytical error.
Inputs and read state
Read between 20:53 and 21:40 +02:00 on 2026-10-03. SHA-256 at first read:
| File | SHA-256 prefix |
|---|---|
report-collection-split-proposal.md |
70fd3814 |
split-drafts/shortened-agentic-systems-contract.md |
81b6d1fe |
split-drafts/analysis-collection-contract.md |
0dc0fd8f |
split-drafts/contract-coverage-check.md |
07abfae6 |
split-drafts/input-coverage.md |
1882af13 |
split-drafts/input-measurements.json |
86d038fa |
kb/agentic-systems/COLLECTION.md |
fb149cfc |
Role-file hashes equal those in input-measurements.json (inputs commit
2b7fe749). Packet code: src/commonplace/lib/agentic_workflow.py at the
working tree of that commit. Outcome sources: fresh-run audit,
second-run audit,
Sol run follow-up plan and the two
trace-evidence files. Raw traces and run state were not read.
Counting rules
Mandatory input. For a role and candidate, the mandatory input is:
- the job instruction;
- the read-first files that
AnalyseAgenticSystem.job()adds for that role; - the candidate's collection contract;
- the root
AGENTS.mdclauses that bind writers.
Under the incumbent, the contract is mandatory by AGENTS.md L138 although
the packet omits it. Under both candidates, the packet supplies the contract
as read-first, as contract-coverage-check.md and implementation-plan.md
specify. Task inputs (boundary, members) are data. They count only where a
rule makes the worker derive something from them. File abbreviations are in
the JSON files map: J job file, W worker rules, B/S/R boundary/sources/records
contracts, RT/MT/ET/CT/OT member types, C collection contract, A AGENTS.md,
D:* definition notes, LV link vocabulary.
Concerns. Count distinct activities, not clauses. An activity counts when the mandatory input gives at least one rule for doing it and the role does not perform it. The ten activities are A1 to A10 in the JSON. Not counted:
- statements that only tell the worker what to omit or who owns a task, because they govern the worker's own output;
- assembly mentions without a rule;
AGENTS.mdrules for other activities. About ten such groups (commits, tests, tags, mailbox and others) apply to every role in every candidate. The JSON lists them underroot_doctrine_concerns_constant; they cannot differ between candidates.
Model-resolved references. Count each reference the worker must resolve to act on a rule that applies to its own output. The three kinds are:
- a rule naming a file the packet does not supply;
- a path the worker must derive;
- a definition reachable only by a link.
A registered AGENTS.md term used technically counts, because AGENTS.md
L51-52 requires reading its linked definition. An unregistered linked term
counts only when the loaded text gives no usable definition. Not counted:
- links to files already in the packet;
- conditional routes whose condition never arises for the role;
- permissive link grammar.
Authority conflicts. Count pairs of loaded instructions that give different answers to one question about this role's output, so the worker must choose. A constraint enforced only by a validator is not a loaded instruction. I list such constraints but do not count them.
Output obligations. Count one obligation per:
- required frontmatter field;
- required section or block;
- record kind's field set;
- controlled vocabulary;
- named cross-record or format constraint.
Conditional record fields and theory properties count once each. Consumers are the downstream readers named in the inputs or code. The flag marks an obligation whose only terminal consumer is publication or cross-system comparison.
Composition depth. For each obligation, count the rule-bearing files the
worker must combine: method files, the collection contract when it states part
of the requirement, and definition notes that root doctrine requires.
A pointer that only routes to another file counts zero. Task data files and
AGENTS.md writing style are excluded from depth. The data files would add one
to three to cross-record obligations in all candidates alike.
Measures per role
Concerns
| Activity | Incumbent | Shortening | Split | Role files (all candidates) |
|---|---|---|---|---|
| A1 publication | L89-90, L99-131 | L35-38 | — | boundary J L16, L25 (opening); OT L52, L56-57 (synthesis roles) |
| A2 comparison reading | L9-15, L89-90, L128-130, L135 | L39-41 | — | OT L56-57 (synthesis roles) |
| A3 review/ordinary accounts | L22-23, L106-108, L117-118, L163-164, L173, L175-177 | L15, L36-37, L45-49, L75, L77-79 | — | — |
| A4 comparison writing | L23-24, L174 | L15-16 | — | — |
| A5 method authoring | L19-21, L26-74 | L14-20, L49-50, L56-57, L80 | L16, L32-34, L43 | — |
| A6 migration | L92-97 | L30-33 | — | — |
| A7 retained/archive | L85-90 | L27-30 | L20-22 | R L24-26 (all roles but boundary) |
| A8 transfer state | L159 | L61-62 | — | — |
| A9 run lifecycle | L78-83 | L22-25 | L15-16 (run state) | — |
| A10 note authoring | L172 | — | — | — |
Not counted as concerns, as stated mentions: memory J L89-90 ("publication
checks them again"), MT L15 (profile authoritative), memory J L44-45 (no
comparison needed), and the assembly mentions in the boundary, epistemic and
verify inputs. The proposal names opening and memory's publication mention.
I count opening because it makes the worker read publication metadata. The
memory mention is not counted because it governs the analyst's own checking.
Model-resolved references
| ID | Roles | Candidates | Reference |
|---|---|---|---|
| REF-COLL | all | incumbent | AGENTS.md L138 needs the target COLLECTION.md; the packet omits it, so the worker derives the path |
| REF-TB, REF-AT, REF-RF, REF-ER | all but boundary | all | Registered terms theory builder, addressable theory, representational form and explanatory reach (R L115, L193, L211, L218-221); definitions not in any packet |
| REF-SI | synthesize, verify-synthesis | all | OT L87 self-improving link, no inline definition |
| REF-BK | verify | all | whole-system and coverage-table semantics in B L40-57, not in the verify packet |
| REF-SETLINK | synthesize | all | member links resolved from a retained directory that does not yet exist (J L48-49) |
| REF-INC-LINKNOTES, -SEARCHNOTES, -SCANREF, -LV | runtime, memory, epistemic, synthesize | incumbent | incumbent L157, L172, L176, L168 |
Authority conflicts
| ID | Roles | Candidates | Pair |
|---|---|---|---|
| CF-READ | all | incumbent | AGENTS.md L138 against the packet list and W L36-40 (do not reconstruct paths). AGENTS.md L157-158 offers a third reading |
| CF-PRIOR | all | incumbent, shortening | incumbent L173-174 or shortening L75-76 link grammar against W L141-153 prior-analysis prohibition |
| CF-PROMOTE | all | incumbent | incumbent L172 (promote a claim to kb/notes/) against W L51-60 write scope |
| CF-EVLINE | boundary, reconcile, verify, synthesize, verify-synthesis | incumbent | incumbent L135 evidence-basis line against "exactly these sections" grammars |
| CF-SETLINK | reconcile | all | contract kb/notes/ link grammar against CT L51-52 set-directory links |
| CF-BLOCKED | memory | all | MT L29-36 blocked report against W L36-41 problem report |
Not counted, listed as a validator-only constraint: every contract, including
the split draft (L38, L41), permits local links to kb/sources/ or
kb/notes/. agentic_set_member_link_failures refuses any local link that
leaves the set directory for runtime, memory, epistemic, reconciliation and
synthesis outputs.
Output obligations and composition depth
The JSON obligations lists every obligation with its sources, files, consumer
and flag. The incumbent adds two obligations to each record-declaring analyst
and one or two to other roles: the evidence-basis line and the link to defining
notes. It also adds itself as a file to up to five theory obligations per analyst,
to boundary's evidence tier and to synthesis's theory statements.
The candidates differ only in which contract line states the native-operation
and transfer-exclusion rules. Both rules have the same depth under both
candidates.
Obligations above depth two under both candidates:
- boundary: disposition (3), Boundary and evidence (3), Source register (3), not-allowlist (4).
- runtime: Runtime account (3), guarantee fields (3).
- memory: component and object fields (3 each),
representational_formaxis (3), axis field structure (3), Boundary and evidence (4), Read-back (3), Integration issues (3). - epistemic: object fields (3), Source-and-claim boundary (4).
- reconcile: amendment, supersession, split, part, missing part, unresolved conflict (3 each), profile check (5).
- verify: record verification content (3), profile check (4), problem versus blocker (3).
- synthesize: theory statements (4), organization (3), amended records (3).
- verify-synthesis: type conformance (5).
Flagged obligations: memory's 14 profile obligations (comparison). Reconciliation's and verification's profile checks (comparison). Reconciliation's set-directory links and synthesis's set-directory links (publication or retention move). Standalone readability in synthesis and verify-synthesis (publication; the stated reason is the generated review). No boundary, runtime or epistemic obligation is flagged.
Interference check
contract-coverage-check.md counts 12 rule groups without a worker-output
decision in shortening and 3 in the split. Every group it lists is present
in the drafts as described. It misses some groups.
| Candidate | Audit | Missing, not foldable | Granularity only | My count |
|---|---|---|---|---|
| Shortening | 12 | layout migration (L30-33); run method commit (L24-25); retained naming and new-run correction (L27-28); comparison-reader rules and trial clearance (L39-41); local retained-analysis links (L76) | reviews/comparisons placement (L14-16); validation marker (L22-23); instruction-authoring conventions (L49-50); ordinary descriptions (L48-49) | 17 at audit granularity, 21 at mine |
| Split | 3 | local-type link rule (L43); area roles (L26-27) | retained frozen (L20-21), foldable into the archive row | 5 at audit granularity, 6 at mine |
Clauses addressing other artifact classes, counted by sentence or list item. Routing exclusions that govern the worker's own omissions are not counted.
- Shortening: 27. L14, L15-16, L16-17, L17-18, L19, L20 (two), L24-25, L27-28, L35, L36 (two), L36-37, L37-38, L40, L40-41, L45, L46-47, L48-49, L49-50, L56-57, L61-62, L75, L77, L78, L79, L80.
- Split: 4. L6, L15-16, L33-34, L43. All four concern run state and local types, which the split collection itself owns.
Neither count is zero, so the proposal's rule prefers the split. The split's residual can move to type specs. The shortening's residual needs a new route for reviews, comparisons and method rules.
Literal-path check
From agentic_workflow.py L744-820 and workflow/job.py and
workflow/engine.py:
- The prompt names the job instruction literally ("Follow
"). - Read-first is worker rules plus the role's extras, as absolute paths.
- Task inputs are absolute paths.
- All three groups are in
Job.inputs.engine.input_statehashes their bytes through_files_state.
Inputs that do not reach the worker as literal paths or do not participate in hashes:
| Input | Literal path | Hashed | Candidates affected |
|---|---|---|---|
| Collection contract | no | no | incumbent as deployed. Both drafts specify read-first and hashed inputs; code is not changed |
AGENTS.md |
no (harness-loaded) | no | all |
| Registered definitions TB, AT, RF, ER | no | no | all record roles |
self-improving-system.md |
no | no | synthesis roles |
| Boundary contract for verify | no | no | verify |
Member schemas (*.schema.yaml) and overview schema enums used by validators |
no | no (validators are outside input state by design) | all; the fresh-run runtime worker read a schema to repair |
| Run state | literal parameter | no (explicitly mutable, L760) | all |
| Frozen checkout | literal parameter | no (pinned by commit, not bytes) | all |
| Link vocabulary | no | no | incumbent analysts and synthesis (L157 makes linking mandatory) |
| Method maintenance | no | no | conditional route; correct by design for workers |
The split additionally changes the type paths that TYPES builds. Those stay
literal and hashed once the constants change.
Outcome baseline
Sources: the fresh-run audit (run -01, 13 sessions), the second-run audit (run -02, 17 sessions) and the Sol plan (Graphiti run -05, stopped). Counts are failures named in those records. They are not complete error censuses.
| Role | Refused submissions | Self-validation failures | Failed reads or paths | Returned findings against the role | Rules read, not applied | Survived publication |
|---|---|---|---|---|---|---|
| boundary | 0 | 0 | -05: quote batch key | 0 | -02: truncated read not reread | -01: whole-system label over an allowlist; -02: register overstates inspection |
| runtime | 0 | -01: 1 draft (headings, order) | -02: duplicated scratch path | 0 | -01: type template headings | — |
| memory | -02: 1 (quote altered) | -01: 2; -02: 2 (delimiter; 6 part fields, validation pending) | -05: contract guessed path, guessed source path, empty quote | -02: 2 profile support; -05: decay axis, combined property parts | Part of grammar (-01, -02, first repair reintroduced it); validation pending (-01, -02) | -02: duplicate identity MEM-OBJ-1 |
| epistemic | 0 | -01: 2; -02: 1 | -01: malformed selection JSON (2 commands), non-verbatim selection; -02: /tmp selection; -05: contract guessed path, guessed source path |
-01: EPI-OBJ-8 containment; -02: evaluator file outside coverage; -05: identifier, ledger and claim-column amendments | ranges (-01, -02); controlled route-function values (-01, -02); scratch rule (-02) | — |
| reconcile | -02: 1 (range) | not recorded | 0 | -01: missed containment (verifier blocker) | range (-02) | -02: duplicate identity missed by 3 rounds |
| verify | -01: 2 (ranges) | n/a | -01: reconstructed type path, fabricated source path, 2 duplicated-segment reads | 0 | ranges (-01) | -02: duplicate identity missed by 2 verifiers |
| synthesize | -02: 1 (range) | n/a | -01: workdir missing slash | -02: missing self-improvement assessment | range (-02) | — |
| verify-synthesis | -01: 1 (ranges) | n/a | -01: JavaScript syntax error | 0 | ranges (-01); truncation recovery incomplete (-01 retry) | — |
All sessions in -01 and -02 also returned r.output instead of the complete
command result, against W L66-97.
Matches to the measures, where supportable:
- Model-resolved references. REF-COLL matches the two Graphiti wrong-path reads exactly, and CF-READ matches the 30 Dynamic Cheatsheet sessions that skipped the contract. Both candidates as designed remove both. The other path failures were transcription errors of literal supplied paths, so literal supply does not prevent every path failure.
- Concerns and the remaining conflicts. No record matches them. No Dynamic Cheatsheet worker loaded the contract. The Graphiti analysts read it whole, but the plan records no consequence. CF-BLOCKED was never exercised. The records are too thin to test whether concerns degrade analyst output.
- Output obligations. Lexical lapses fall on depth-one and depth-two obligations: no-ranges, route-function values, Part of grammar, validation pending, template headings and quote literalness. Semantic findings fall on depth-three-and-above or flagged obligations:
- containment and identity: REC-partof, REC-supersession, VER-content;
- profile support and decay: MEM-axis-fields, curation axis (flagged);
- coverage: EPI-block1, BND-not-allowlist;
- theory: SYN-theory.
The duplicate identity also involves MEM-overlap (depth two). This split is an observation over three runs and one model family per run. It is not a test.
Deviations and limits
- Incumbent variants. The incumbent is reported as deployed, with the contract mandatory but unsupplied. The Result also gives incumbent plus packet entry. Alternative: count only packet-supplied files for the incumbent. Its concerns would then fall to 1-3 per role, below both candidates, and CF-READ would remain. The proposal and coverage check reject omission as a saving, so I did not use this reading.
- Concerns unit. I counted activities, as the measure says. Counting
clauses instead gives the interference-check numbers: 27 for shortening, 4
for the split. Treating
openingas data rather than a publication rule lowers boundary by one in every candidate. - Permissive link grammar. I counted CF-PRIOR as a conflict. Not counting it makes shortening equal the split on all three measures for boundary, runtime and epistemic. Memory would then be 1/1 on conflicts. Concerns would still differ.
- Definition references. I counted registered definitions as references
because
AGENTS.mdL51-52 requires reading them. Not counting them lowers references by four for record roles in all candidates. It does not change the comparison. - Root doctrine in context. I did not verify from traces that
AGENTS.mdwas in every worker's context; I relied on the proposal's statement. - Composition depth excludes task data and counts definition notes only where root doctrine requires them.
- Obligation granularity is my choice: for example, one obligation per memory axis, and one per record kind. Another reasonable granularity would change totals, not the candidate comparison. The candidates differ by the two incumbent-only obligations alone.
- Graphiti run used a different model and worktree, and its code changed during the run. Its correction worker's malformed YAML frontmatter is not in the outcome table because the plan does not name that worker's role; the plan's pointer to the memory job suggests the memory correction round.
- Not verified. Both candidates' packet changes (read-first entry and hashing) exist only as drafts. Validator behaviour on links was read from code and not exercised.