Skip to content

A course install can truncate mid-copy with nothing logged — 8 of 9 declared roots landed, no error #2014

Description

@rbuergi

Observed on MeshWeaver.Education run 32503778979, shard 2's retry. Filed separately from Education#192 (which fixes an unrelated harness premise in the same run) because this is a product defect and should not ride along in a test-harness PR.

What happened

Installing ThinkInStreams copied 8 of its 9 declared roots and stopped.

run batches total
08-19 (good) 11,9,10,10,9,9,9,9,10 86
08-21 (truncated) 11,9,10,10,9,9,9,6

The last batch is short and the ninth never runs. Result: e2e-admin/ThinkInStreams/09-RxVersusIx/Exercise/OperatorForge/Source/OperatorForge is absent — No node found, portal log 17:08:38.

Nothing was logged. No error, no warning, no failed phase.

What the engine got right

The Store install engine did not claim success: no _Install record was written. That is the ProvisionPlan contract working as designed — "a failing phase fails fast, NAMES itself, and the remaining phases are never subscribed — so a partial install is structurally unable to record itself as installed."

So this is not "the learner is marked installed with missing content". It is narrower and still bad: the copy stopped, silently, and only the absence of the record distinguishes it from success.

Why it matters anyway

  • A learner hitting this sees an install that did not finish, with no error to report and nothing naming what is missing. The self-heal path re-installs, which may or may not truncate again.
  • The truncation is content-dependent or timing-dependent — the same course copied all 9 roots two days earlier. That makes it a race or a bounded-batch edge, not a bad declaration.
  • It was caught only because Education#191 tightened the workbench probe. A looser probe would have passed over an install that had lost the learner's workbench — which is how this could have been live for some time without anyone noticing.

Where to look

Localizer.LocalizePlan executes root-by-root, sequentially, with ProvisionPlan.Sequential inside each root — the ordering that replaced the old concurrent Merge(roots, 3) × Merge(writes, 4). The batch sizes above suggest the writes are still being chunked; a chunk boundary that ends a root early, or a root whose subscription completes without emitting, would produce exactly this shape without an error.

The verify phase (VerifyInstalled against DeclaredInstallPaths) is what should have caught a missing root and failed loudly. Worth establishing whether it ran at all here — if the chain terminated before reaching it, the verify cannot report, which would make "no record written" the only signal.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions