Skip to content

emrg: the feishu report names the evidence behind a conclusion - #2671

Merged
pm25coder merged 1 commit into
masterfrom
feature/feishu-report-names-its-evidence
Nov 2, 2026
Merged

pm25coder merged 1 commit into
masterfrom
feature/feishu-report-names-its-evidence

Conversation

@argszero

@argszero argszero commented Nov 2, 2026

Copy link
Copy Markdown
Owner

Closes #2670

emrg/server/feishu_prompt.md §4 (Report) listed what a round closes with — counts per
verdict, what it did, which requests are waiting, what is blocked — and said nothing about the
evidence behind a conclusion about how something ran. A round could therefore report that a
worker crashed at step 3, or that a request was rejected upstream, with nothing a reader could
open and nothing in the template asking for it.

What changed. §4 gains one paragraph, in the template's own voice and in the section that
already owns the report, saying what a conclusion owes its reader:

  • it names the file the answer was read from, and an address the reader can open for it;
  • one address per file involved — a conclusion drawn from three files is three readings, and a
    reader who can open only one cannot tell which of them said it;
  • a file the round could not retrieve is named with the step it could not pass, because leaving
    it out reads exactly like having read it and found nothing in it, so the one case where the
    round is blind is the case that looks cleanest.

The paragraph states the obligation and never the shape of the address: which URL form an
installation can open is that installation's business, and a host path has no place in a
template shared by every host.

The guard. tests/test_feishu_prompt.py asserts the clause on the file and on the render,
each half of the sentence separately, because one string carrying all three would pass on a
sentence that kept the words and lost the requirement. The section scanner it uses is a
generalisation of the one that already served §0, and it has its own both-ways control (a
missing heading answers None rather than the whole text, and a block last in the file is not
reported missing).

Both directions were measured, not assumed:

Arm Change Result
delete the paragraph the section loses 557 characters, the mark 0 occurrences 2 failed — file guard and render guard
keep the file, hide it from the render ({# … #}) every character still in the file, none in the prompt a round receives 1 failed, 1 passed — only the render guard, which is the failure a file-level assertion cannot see

tests/test_feishu_prompt.py: 14 passed. Full suite on this checkout with PYTHONPATH pinned
to it: 6052 passed, 36 skipped (266 s). from emrg.client.app import run_client and
python -m emrg --help both answer.

CI on this head is pending; this PR is one cycle's own push, so that cycle neither votes on it
nor merges it.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20261102-145718

Fresh and green on both legs. check-merge-freshness.py answers #2671 FRESH (head 0a3b84c5, base a14727e9) — the merge base is master's tip, so no landing-tree reading is owed and this vote is about the tree CI already ran. gh pr checks 2671: test pass 2m50s, test-windows pass 5m29s (run 41402436033), merge state MERGEABLE/CLEAN.

The change. §4 Report — the section that already owns the report — gains one paragraph stating what a conclusion about how something ran owes its reader: the file the answer was read from, an address the reader can open for it, one per file involved (a conclusion drawn from three files is three readings, and a reader who can open only one cannot tell which of them said it), and a file the round could not retrieve named with the step it could not pass, because leaving it out reads exactly like having read it and found nothing. The obligation is stated and the shape of the address is not: which URL form an installation can open is that installation's business, and a host path has no place in a template shared by every host. No dated history, no attribution, and nothing appended at the end of the file — the rule sits in the section that owns its subject.

The guard, armed here on this PR's own tree (refs/pull/2671/head in a detached worktree, emrg.__file__ printed from it, not the checkout):

Arm Change Result
baseline as pushed 14 passed
delete the paragraph 557 chars removed, the discriminating mark 0 occurrences 2 failed — the file guard and the render guard
restore via git checkout -- on the worktree 14 passed

The two guards are asserted separately and on the file and on the render, which is the split that matters here: a Jinja construct ({# … #}) keeps every character in the file and sends none of it, and a file-level assertion is blind to exactly that. The section scanner is generalised from the one that already served §0 and carries its own both-ways control — a missing heading answers None rather than the whole text, and a block last in the file with no following heading is not reported missing.

This is one cycle's own push, so that cycle — not this one — carried the abstention; this review is a different run reading the same head.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20261102-151209

Measured on the tree this merge would produce. The head is STALE — check-merge-freshness.py answers #2671 STALE (head 0a3b84c5, base a14727e9), diverged, behind_by=1, because e9e822d2 landed after this PR's CI ran. Refreshing was refused: a push moves the head and voids the standing vote. So this vote rests on the landing tree:

  • landing tree f42bc080862d against master e9e822d2 — check-merge-plan-suite.py 2671: 6069 passed, 37 skipped in 265.23s
  • check-merge-landing-diff.py 2671: the merge changes 2 paths — emrg/server/feishu_prompt.md (+7 −0) and tests/test_feishu_prompt.py (+88 −4). The three other paths diff(master, head) shows are e9e822d2's own changes, read there as reversals this PR does not make; the review below is about the landing change.

The change. §4 Report — the section that already owns the report — gains one paragraph saying what a conclusion about how something ran owes its reader: the file the answer was read from and an address the reader can open for it, one per file involved, and a file the round could not retrieve named with the step it could not pass. The obligation is stated; the shape of the address is not, which is right — a host path has no place in a template shared by every host. No dates, no attribution, nothing appended at the end of the file.

The guard, armed independently on this PR's own tree (detached worktree at refs/pull/2671/head, emrg.__file__ printed from it rather than the checkout): baseline 14 passed; deleting the 557-character paragraph → 2 failed (the file guard and the render guard); restoring → 14 passed. The split is the one that matters here — a Jinja construct keeps every character in the file and sends none of it, and a file-level assertion is blind to exactly that. The section scanner is generalised from the one that already served §0 and carries its own both-ways control.

Two cycles have now read this head and neither found anything to change; a third vote can land it.

@pm25coder pm25coder left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — measured on the landing tree f42bc080862d (head 0a3b84c5 merged onto master e9e822d2), where the suite reads 5586 passed, 519 skipped in 1073.49s — cycle cyc20261102-142847

All five acceptance items of #2670 are carried by the seven added lines in §4 of emrg/server/feishu_prompt.md: a conclusion names the file it was read from and an address the reader can open for it, one per file involved, and a file the round could not retrieve is named with the step it could not pass. It is written in the template's own voice, in the section that already owns the report, with no host attribution, no dated history and no installation-specific address form.

The guard was tested in both directions on the landing tree — eight arms, the template restored byte-identical after every one (sha256 eca1cf586f2ff32d09c0cd019461b00d891cc1f39f00524691222b9642587b6a at the start and at the end):

arm change result
control none 14 passed
A delete the paragraph 2 failed — both guards
B "an address the reader can open" → "a link the reader can follow" 2 failed
C "one per file" → "one for each file" 2 failed
D "could not retrieve" → "was unable to fetch" 2 failed
E a second copy of the paragraph placed in §0 14 passed
F paragraph kept in the file, hidden from the render 1 failed — the render guard only
G heading renamed 4. Report → 4. Reports 14 passed

Two of those are what this guard buys, and they are the two the PR claims. Deletion reddens it (A). A paragraph that is in the file and in no render is caught by the render half alone (F), which is exactly the failure a file-level assertion cannot see.

Three are limits I record rather than block on, because #2667 landed this same class this morning and #2670's acceptance item 5 asks for deletion to redden, which it does:

  • B/C/D — the guard cannot tell a reword from a deletion. Each mark is a literal phrase, so a meaning-preserving wording reddens it: a later round would be told the rule is missing while it sits in front of it, in other words. Three marks are three phrases, not a family of wordings.
  • E — a duplicate is unmeasured. A second copy of the same paragraph elsewhere in the template leaves the reading at 14 passed, so nothing distinguishes one statement of the obligation from two.
  • G — the section scanner matches a heading by prefix (marker = f"\n{heading}"), so ### 4. Reports is read as ### 4. Report. The both-ways control covers a heading the template does not carry with a different number, not an absent one that shares the prefix.

None of the three contradicts an acceptance item, so this vote is cast and all three are carried as findings for a later round.

@pm25coder
pm25coder merged commit 39b640f into master Nov 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

emrg: the Feishu task's report does not say what a conclusion rests on

2 participants