Repository navigation
feat(scorers): expose delivered team skills in session evidence - #1561
ousamabenyounes wants to merge 5 commits into
Conversation
…ent#1469) A session judge could not tell which team skills a session was delivered or which it loaded: evidence.json held only the subject, kind and gaps, and the judge never read the label's used.skills. This lands the evidence-only slice of Tencent#1469 (which the issue notes can ship first, independently of the Tencent#1180 reserved-name work) so a later change can add the routing questions on top. At session start the capture now records, per delivered team skill, the frontmatter description its SKILL.md then carried and the skills namespace it came from (deliveredTeamSkillInfo), beside the existing name->files record. A session's own pull adds the skills it delivers with the description they then have; a later pull changes nothing. judgeSession builds a skills block for the manifest from those captures: skills.available is the union across captures (latest description of a name wins, each masked with the scope mask, a root skill has no namespace) and skills.used is the label's bare names, unchanged. A checkout with no team skills yields skills: { available: [], used: [] } and no gap; a session whose captures recorded no descriptions (for example one captured before this change) gets no skills key and the new skills_unknown evidence gap. The Tencent#1399 scorer-file control now reads the session's own captures instead of none, so it keeps skills.available. Out of scope here (left for the follow-up): skill_routing, the scorers/scoring.yaml key, and the per-skill routing scorer names. Tests: unit tests for the skills manifest (gap, empty, union/latest, masking), the capture's descriptions and namespaces, and judgeSession's manifest; real upstream RED proven before the change, GREEN after. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
There was a problem hiding this comment.
This was generated by AI during triage.
@ousamabenyounes Thanks, the feature works. With the built CLI on this head, I ran a team with both ops/ship and web/ship, a role switch with teamai roles set ops without a pull, then a session and its score. Against #1469:
- The capture keeps the
webcopy the session actually held. skills.usedmatches the label.- A later pull leaves the captured description unchanged.
- Captures from main give the
skills_unknowngap. - A team with no skills gives
available: []and no gap.
tsc and lint pass. The three changed test files pass (28) and fail on main. CI is green at this head.
One thing blocks merge.
- [P1 blocking] No real-CLI record of the feature. The body's only built-CLI step is
node dist/cli.js --version. "Testing before a PR" in AGENTS.md asks for an end-to-end run of the changed behavior. Please paste one built-CLI run: a session capture, then the scoring path, ending in anevidence.jsonwithskills.availableandskills.used. The CI review raised the same point.
Non-blocking:
- [P2 non-blocking] No delivery record at session start. A team with no skills, where the session starts before any delivery record exists, gets
skills_unknownrather thanavailable: []. #1469's scope sentence ("a capture that read the delivery record") supports this. The body and criterion 5 read looser, though, so please align one of them. - [P2 non-blocking] Namespace from the clone's manifest. It is read from the team clone's current manifest (
src/skill-use.ts:321), as the CI review says. I could not move the clone without this checkout's pull, so this is not reproduced. Can another workspace on the same machine advance the clone in between? If so, a deliveredweb/shipcould be labelledops. - [P2 non-blocking] Unquoted colon in a description. A description such as
description: Cut an npm release: bump, changelog, tag, publish.is recorded as""with no gap.parseFrontmatterdrops thevalidflag thatsplitFrontmatterreturns. A gap, or a note for the routing slice, would keep later routing from reading an empty description as real. - [P2 non-blocking] Scorer guide.
docs/guide/scorers.md(and zh-CN) do not mention the newskillskey andskills_unknowngap that scorer files now see. Fine to defer to the routing slice if you say so. - [P3 nit]
deliveredTeamSkillInforepeats the walk indeliveredTeamSkills(src/skill-use.ts). One walk would keep a single copy of the rule.
@jeff-r2026 Your call on this one. The evidence-only slice matches what #1469 allows before #1180's routing scorer.
Resolved: The earlier empty post-pull inventory finding is fixed: an observed delivery now preserves Review was read-only; no PR code was run, built, or installed. |
SaulMoro
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
@ousamabenyounes Thanks, most of the last round is in. Checked again at d06896ef with the built CLI:
- Real-CLI record: resolved. The body now has a built-CLI run from session start to score, and CI's e2e shards pass at this head.
- No delivery record at session start: resolved. It now gives
available: []with no gap. - Namespace from the clone's current manifest: partly resolved. With two namespaces holding
ship, it now sayswebwhere the last head saidops. That holds when SKILL.md has bothname:anddescription:. See the third point below for when it does not.
What the new commit adds:
- [P2 non-blocking, should be fixed here] Session start runs
git showfor every delivered skill. The loop insrc/skill-use.ts(around line 350) reads each skill's source at the pull's revision withgetFileContentAtRev, even for names that exist in only one namespace. The session-start hook is synchronous, so members wait for this on every session. With 150 delivered skills the hook went from 0.5–1.1 s to 1.4–2.5 s. The machine was under load, so only the ratio counts. Comparing hashes only for names found in more than one namespace keeps the fix and drops most of the cost. The same line also adds a non-null assertion,deliveredRev!, inside a block that already checkeddeliveredRev. - [P2 non-blocking] A deleted skill shows in
availablebut never inused. I reproduced it with a skill the team deleted after the member's last pull. It is still listed as available, but loading it in the session does not add it toused. The previous head left it out of both lists. - [P2 non-blocking] The hash comparison misses skills that pull rewrites. When pull delivers a SKILL.md, it adds a missing
name:(anddescription:), so the delivered file never hashes the same as the source. For those skills the namespace falls back to today's manifest. I reproduced this. It contradicts the body's provenance sentence, and the e2e fixture skill has noname:. Hashing the rewritten source, asisRecordedFromTeamSkilldoes, fixes it. - [P3 nit] Identical copies in two namespaces still resolve through today's manifest, as the CI review says. I agree, but it needs an unlikely setup.
Still open from the last round: an unquoted colon in a description is recorded as "" with no gap, the scorers guide does not mention the new fields, and the skill walk is duplicated. The duplicated walk is what doubles the session-start cost above.
tsc, lint and the three changed test files (29) pass, and CI is green at this head.
@jeff-r2026 Your call. The session-start cost is the item I'd want fixed before this lands.
Resolved: The single-namespace historical-role scenario and empty post-pull inventory are fixed. The updated description documents a passing real hook → score flow that checks Review was read-only; no PR code was run, built, or installed. |
Resolved: The prior namespace-relabeling and empty post-pull inventory findings are fixed. The description now records a passing real hook → score flow checking Review was read-only and limited to the specified diff; no PR code was run, built, or installed. |
|
No new findings confidently established in the specified diff. Resolved: The ambiguous-namespace case now preserves the delivered skill and description with Testing: The PR description documents a passing real session-start hook → score CLI flow that checks Review was read-only and limited to the specified diff; no PR code was run, built, or installed. |
SaulMoro
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
@ousamabenyounes Checked again at cad3302c. The new commits fix the CI review's point about identical copies: the built CLI now says web where d06896ef said ops. The points from my last comment are still open:
- [P2 non-blocking, should be fixed here] Session-start cost. Session start still runs one
git showper delivered skill. With 150 delivered skills on an idle machine, the hook takes 0.96–1.07 s at this head, against 0.31–0.44 s ate87ad0bc, about 3x. Only names delivered from more than one namespace need the hash comparison. - [P2 non-blocking] Missing
name:line. Skills whose SKILL.md has noname:line still get today's namespace (ops). Pull addsname:on delivery, so the delivered file never hashes like the source. Hash the rewritten source, asisRecordedFromTeamSkilldoes. This also contradicts the body's provenance sentence. - [P2 non-blocking] Deleted skill. A skill the team deleted is listed in
availablebut never inused, even when the session loaded it. - Still open from before: an unquoted colon in a description is recorded as
""with no gap, the scorers guide does not mention the new fields, and the skill walk is duplicated.
New in these commits:
- [P3 nit] A skill delivered through a project namespace now gets
namespaceUnknown, whered06896efgave the correctops. The delivered namespaces are built from roles only, not roles plus projects. - [P3 nit] There is a new non-null assertion,
deliveredRoleNamespaces!, atsrc/skill-use.ts:370, and the line that reads the description is duplicated.
Build, tsc, lint and the four changed test files (68) pass, and CI is green at this head.
@jeff-r2026 Your call. The session-start cost is still the item I'd want fixed before this lands.
Summary
A session judge currently sees neither the team skills delivered to the session nor the skills it loaded. This PR adds the evidence-only slice of #1469: captures retain each delivered skill's description and actual namespace, and
evidence.jsonexposesskills.availableandskills.used. The issue explicitly allows this slice to land before the blocked routing-scorer work in #1180.The capture uses the member's saved delivery selection and checks the delivered skill against source files and the role manifest at that pull's revision. Thus, when
ops/shipandweb/shipexist, a role switch or a later role-manifest edit cannot relabel an unchangedwebcopy asops. When two historical copies have identical content and the delivery record cannot distinguish them, the capture keeps its name and description withnamespaceUnknown: truerather than assigning today’s namespace. An own-pull delivery with no skills is recorded as an empty inventory. Descriptions are masked before entering the evidence manifest. Older captures get theskills_unknowngap; a captured checkout with no team skills gets an emptyavailablelist. The scorer-file control now receives the session's captures too.Type of change
Test plan
npm run buildand real CLI E2E:hook-dispatch session-start→score --session→ fake judge readsevidence.jsonwith the delivered skillnpx tsc --noEmitoxlint --deny-warningson the changed filessrc/__tests__/e2e/score-session.test.tspass; the earlier coverage run covered 100% of 126 executable added lines before the final ambiguity guardRED → GREEN evidence (selected test log lines)
Full-suite baseline comparison
The full-suite failures include tests requiring tools or process behavior absent in this container. For example, the seven
env-execfailures reproduce unchanged when that file is run alone on both base and branch. The focused tests, typecheck, build and changed-file lint are green.Real CLI E2E execution
The E2E harness invokes the built CLI (
dist/index.js) withhook-dispatch session-start --tool claude, thenscore --session <fixture-id> --source claude-code --scorer review-quality. Its fake judge reads the generatedevidence.json. The passing assertion checksskills.availablecontains the deliveredreview-notesskill with its description,skills.usedis[], andskills_unknownis absent.Related issue
Part of #1469. Routing questions,
skill_routingsettings, generated scorer names and documentation for those settings remain in the follow-up after #1180; this PR does not close #1469.