Skip to content

feat(operator-surface): cut over shared operator surfaces#192

Merged
MacAttak merged 5 commits intomainfrom
work/03-operator-surface-cutover
Apr 20, 2026
Merged

feat(operator-surface): cut over shared operator surfaces#192
MacAttak merged 5 commits intomainfrom
work/03-operator-surface-cutover

Conversation

@MacAttak
Copy link
Copy Markdown
Contributor

Summary

This unit cuts the primary operator surfaces over to a shared closeout and approval summary model, so Claude recovery hooks, the Opencode plugin, and status/setup/health guidance all surface the same human-useful state instead of requiring hidden context.

Approval Lineage

  • design: APPROVED via /sw-plan and still current against the design artifact set.
  • unit-spec (03-operator-surface-cutover): STALE (artifact-set-changed) because plan.md gained ## As-Built Notes after /sw-build captured approval.
  • No accepted-mutant approvals apply to this unit.

What Changed

  • Added adapters/shared/specwright-operator-surface.mjs so Claude and Opencode render the same closeout and approval summary.
  • Cut adapters/claude-code/hooks/session-start.mjs and adapters/opencode/plugin.ts over to the shared state/operator-surface helpers without dropping lock, ownership, shipping, or continuation warnings.
  • Updated build/build.sh and adapters/opencode/package.json so the shared helper ships with the Opencode adapter.
  • Tightened core/skills/sw-status/SKILL.md, core/skills/sw-init/SKILL.md, core/skills/sw-guard/SKILL.md, and core/skills/sw-doctor/SKILL.md around closeout visibility, approval reason visibility, and explicit git.runtime.* guidance.
  • Added regression coverage in evals/tests/test_operator_surface_visibility.py, tests/test-hooks.sh, tests/test-opencode-plugin.sh, and tests/test-config-validation-visibility-docs.sh.

Why The Agent Implemented It This Way

  • Centralized closeout and approval rendering so the operator-facing surfaces cannot drift into separate wording or separate state-root assumptions.
  • Kept runtime-mode guidance in tracked skill contracts instead of burying it in implementation details, preserving the separation between runtime roots and tracked work-artifact publication.
  • Preserved the literal review-packet presence wording in sw-status because the full configured test command proved older publication-mode regressions still depend on that phrase.
  • Added a dedicated Python regression harness so the operator-surface contract runs in the normal pytest path, not only through shell-only proofs.

Acceptance Criteria

  • AC-1 PASS
    Implementation: adapters/claude-code/hooks/session-start.mjs:24, adapters/opencode/plugin.ts:186
    Evidence: TestSessionStartSurface.test_session_start_replays_shared_digest_and_approval_summary in evals/tests/test_operator_surface_visibility.py:234, shell hook coverage in tests/test-hooks.sh:565, Opencode wiring assertions in tests/test-opencode-plugin.sh:128
  • AC-2 PASS
    Implementation: adapters/shared/specwright-operator-surface.mjs:10, adapters/shared/specwright-operator-surface.mjs:95, adapters/claude-code/hooks/session-start.mjs:80
    Evidence: TestSessionStartSurface.test_session_start_names_missing_closeout_and_approval in evals/tests/test_operator_surface_visibility.py:223, shell hook coverage in tests/test-hooks.sh:545
  • AC-3 PASS
    Implementation: core/skills/sw-status/SKILL.md:46
    Evidence: TestOperatorSurfaceContracts.test_status_skill_keeps_approval_reason_and_closeout_visibility_together in evals/tests/test_operator_surface_visibility.py:261, doc regression checks in tests/test-config-validation-visibility-docs.sh:79
  • AC-4 PASS
    Implementation: core/skills/sw-init/SKILL.md:124, core/skills/sw-guard/SKILL.md:68, core/skills/sw-guard/SKILL.md:97
    Evidence: TestOperatorSurfaceContracts.test_runtime_guidance_uses_runtime_keys_without_collapsing_into_work_artifacts in evals/tests/test_operator_surface_visibility.py:266, doc regression checks in tests/test-config-validation-visibility-docs.sh:57
  • AC-5 PASS
    Implementation: core/skills/sw-doctor/SKILL.md:65, core/skills/sw-doctor/SKILL.md:83, core/skills/sw-doctor/SKILL.md:94
    Evidence: TestOperatorSurfaceContracts.test_runtime_guidance_uses_runtime_keys_without_collapsing_into_work_artifacts in evals/tests/test_operator_surface_visibility.py:266, doc regression checks in tests/test-config-validation-visibility-docs.sh:72
  • AC-6 PASS
    Implementation: evals/tests/test_operator_surface_visibility.py:223, tests/test-hooks.sh:545, tests/test-opencode-plugin.sh:114, tests/test-config-validation-visibility-docs.sh:57
    Evidence: TestSessionStartSurface.test_session_start_names_missing_closeout_and_approval in evals/tests/test_operator_surface_visibility.py:223, TestSessionStartSurface.test_session_start_replays_shared_digest_and_approval_summary in evals/tests/test_operator_surface_visibility.py:234, plus the recorded commands.test PASS for the full validation path

Spec Conformance

  • AC-1 through AC-6 all passed in the canonical compliance matrix for this unit.
  • This is not the final work unit in workflow-legibility-devex, so behavioral IC-B* criteria were intentionally not evaluated in this unit-level ship step.

Gate Summary

Gate Verdict Findings (B/W/I)
build PASS 0/0/2
tests PASS 0/0/1
security PASS 0/0/0
wiring PASS 0/0/1
semantic PASS 0/0/1
spec PASS 0/0/0

Remaining Attention

  • The gate suite is clean, but the current unit-spec approval lineage is stale and should be refreshed or consciously accepted as stale review context.
  • .specwright/AUDIT.md is currently modified locally but is outside this unit's file-change map and is not part of this PR.

Evidence

This repository uses clone-local work-artifact mode, so the reviewer-usable approval, rationale, conformance, and remaining-attention summaries are inlined above rather than depending on local-only artifact links.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 20, 2026

Eval Smoke Results

✅ Smoke evals clean — 0 regressions, 5 improvements

Eval Pass Rate Duration Tokens (input+output) Verdict
grader-function-tests 1.00 (+0.00) 569ms (-925ms) 0 (+0) improved
structural-handoff-template 1.00 (+0.00) 26ms (-17ms) 0 (+0) improved
structural-skill-validation 1.00 (+0.00) 1164ms (-1394ms) 0 (+0) improved
structural-state-enforcement 1.00 (+0.00) 66ms (-25ms) 0 (+0) improved
workflow-yaml-validation 1.00 (+0.00) 922ms (-378ms) 0 (+0) improved

Posted by Specwright eval-smoke workflow. This comment is updated on each push.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 20, 2026

Code Review — PR #192: feat(operator-surface): cut over shared operator surfaces

Overall this is solid work. The centralization goal is achieved cleanly, and the regression harness (Python + shell) gives good surface coverage. Several issues worth addressing before merge, ranging from a correctness risk to minor hygiene.


🔴 Issues to fix

1. Dead branch in resolveRuntimeWorkRoot (adapters/shared/specwright-operator-surface.mjs:13-19)

The first two branches are byte-for-byte identical — both return join(stateInfo.repoStateRoot, 'work', work.workId). The layout === 'shared' guard has no observable effect and will mislead future readers into thinking the two layout paths differ:

// Lines 13-19 — first guard is dead
if (stateInfo?.layout === 'shared' && stateInfo?.repoStateRoot) {
  return join(stateInfo.repoStateRoot, 'work', work.workId);
}
if (stateInfo?.repoStateRoot) {
  return join(stateInfo.repoStateRoot, 'work', work.workId);  // same
}

Merge into if (stateInfo?.repoStateRoot) and drop the layout guard.

2. Silent error swallowing in summarizeApproval (specwright-operator-surface.mjs:95-101)

A bare catch {} converts every error — including filesystem permission failures, malformed JSON, and unexpected assessApprovalEntry throws — into MISSING/missing-entry. An operator seeing that output has no way to distinguish "file doesn't exist" from "something broke." At minimum, write to process.stderr on non-ENOENT errors so the signal isn't lost.


🟡 Issues to address

3. Capitalization inconsistency in sw-guard/SKILL.md:69

- recommend `project-visible` for Claude-oriented installs ...

Every other bullet point in this section starts with a capital letter (Detect, Confirm, Seed, Keep). This should be - Recommend.

4. No test coverage for the Quality Corrections extraction (adapters/opencode/plugin.ts:150-153)

The new Correction Summary regex block that appends --- Quality Corrections --- to continuationContent is entirely untested. Neither the Python suite nor the shell tests exercise a continuation snapshot that contains a ## Correction Summary section. Given that this is new logic that silently appends extra operator-facing content, it deserves at least one positive and one negative case.

5. approvedAt fixture date is current-date-sensitive (evals/tests/test_operator_surface_visibility.py:715, tests/test-hooks.sh:914)

Both test harnesses hardcode approvedAt: '2026-04-20T00:00:00Z', which matches currentDate. If assessApprovalEntry has any freshness or staleness logic keyed to relative age, the test verdict could silently flip on a future run. Use a fixed past date (e.g. 2026-01-01T00:00:00Z) so the fixture is date-stable.


🔵 Nits

6. resolveWorkPaths — potential baseDir / approvalsPath split when artifactsRoot is absent

resolveApprovalTarget sets baseDir: work.workDirPath for unit-spec approvals, while approvalsPath falls back to join(runtimeWorkRoot, 'approvals.md') when work.artifactsRoot is absent. If workDirPath and runtimeWorkRoot diverge (e.g. publication-mode installs), assessApprovalEntry will hash artifacts relative to workDirPath but read the approvals document from runtimeWorkRoot — a silent stale-assessment path. Worth an explicit comment or assertion.

7. renderOperatorSurfaceLines indent options are unexercised

options.indent / detailIndent / bulletIndent exist and are used internally but are never passed by any caller, and there are no tests for non-default indentation. Either remove the options surface now and add it back when a caller needs it, or add one test that exercises a non-default indent to pin the contract.


✅ Positive callouts

  • The plugin.ts refactor from ad-hoc readWorkflow() + isActiveWork() to loadActiveState() using the shared normalizer is a clean simplification. The type-cast soup from the original (currentWork as Record<string, unknown>) is gone.
  • mkdirSync(dirname(continuationPath), { recursive: true }) before writeFileSync in session.compacted — defensive and correct, and correctly absent from session.created where continuationPath is only read.
  • The write_shared_approvals shell helper passes paths via env vars rather than string interpolation — avoids injection with path characters.
  • The Python _run_session_start helper correctly uses check=False and surfaces stderr before falling through to assertion, making fixture failures debuggable.

Comment thread adapters/shared/specwright-operator-surface.mjs
Comment thread adapters/shared/specwright-operator-surface.mjs Outdated
Comment thread core/skills/sw-guard/SKILL.md Outdated
Comment thread adapters/opencode/plugin.ts
Comment thread adapters/shared/specwright-operator-surface.mjs
Comment thread evals/tests/test_operator_surface_visibility.py
Comment thread tests/test-hooks.sh
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 109db1c863

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread adapters/opencode/plugin.ts
@MacAttak MacAttak merged commit 8b21dea into main Apr 20, 2026
29 checks passed
@MacAttak MacAttak deleted the work/03-operator-surface-cutover branch April 20, 2026 21:33
@github-actions github-actions Bot mentioned this pull request Apr 22, 2026
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.

1 participant