@rubytech/create-sitedesk-code 0.1.524 → 0.1.526
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/samba-provision.test.js +46 -1
- package/dist/__tests__/websockify-bind-wiring.test.js +47 -0
- package/dist/index.js +39 -1
- package/dist/samba-provision.js +37 -0
- package/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +8 -7
- package/payload/platform/plugins/admin/skills/superpowers-sprint/SKILL.md +26 -0
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +12 -0
- package/payload/platform/plugins/memory/PLUGIN.md +10 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js +5 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/temporal-type-preserve.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/temporal-type-preserve.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/temporal-type-preserve.test.js +141 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/temporal-type-preserve.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js +6 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/temporal-type-preserve.d.ts +45 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/temporal-type-preserve.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/temporal-type-preserve.js +122 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/temporal-type-preserve.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.js +26 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-type-preserve.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-type-preserve.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-type-preserve.test.js +201 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-type-preserve.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +89 -33
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/vitest.config.ts +2 -0
- package/payload/platform/plugins/scheduling/PLUGIN.md +6 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-retype.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-retype.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-retype.test.js +148 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-retype.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +83 -6
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +90 -5
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/routine-roster-audit.test.js +173 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/routine-roster-audit.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +73 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +194 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +25 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +81 -8
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-event-agent.test.js +39 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-event-agent.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +9 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
- package/payload/platform/scripts/__tests__/check-canonical-tool-names.test.sh +162 -0
- package/payload/platform/scripts/__tests__/check-no-task-id-leaks.test.sh +53 -0
- package/payload/platform/scripts/__tests__/task-id-citation.test.sh +72 -0
- package/payload/platform/scripts/check-canonical-tool-names.mjs +36 -4
- package/payload/platform/scripts/check-no-task-id-leaks.mjs +80 -62
- package/payload/platform/scripts/lib/canonical-tool-names.mjs +130 -26
- package/payload/platform/scripts/lib/task-id-citation.mjs +67 -0
- package/payload/platform/scripts/vnc.sh +45 -1
- package/payload/server/{chunk-VUXKXOJU.js → chunk-7MGR5M6G.js} +4 -2
- package/payload/server/{manager-4TJK3YOY.js → manager-6XOWHREK.js} +1 -1
- package/payload/server/server.js +10 -4
- package/payload/platform/.docs/search-surface-contract.md +0 -58
- package/payload/platform/docs/superpowers/plans/2026-06-02-task-610-follower-202-retry.md +0 -372
- package/payload/platform/docs/superpowers/plans/2026-06-04-public-agent-knowledge-delivery.md +0 -230
- package/payload/platform/docs/superpowers/plans/2026-06-23-account-filesystem-schema.md +0 -544
- package/payload/platform/docs/superpowers/plans/2026-07-11-task-1557-operator-on-behalf-preference-attribution.md +0 -542
- package/payload/platform/docs/superpowers/plans/2026-07-13-account-schema-ontology-projection.md +0 -547
- package/payload/platform/docs/superpowers/plans/2026-07-14-graph-top-level-labels-ontology-single-source.md +0 -458
- package/payload/platform/docs/superpowers/plans/2026-07-17-task-1736-retire-mcp-stderr-tee.md +0 -397
- package/payload/platform/docs/superpowers/plans/2026-07-18-graph-native-ledger.md +0 -807
- package/payload/platform/docs/superpowers/plans/2026-07-18-ledger-write-path-fix.md +0 -109
- package/payload/platform/docs/superpowers/plans/2026-07-20-storage-pages-create.md +0 -82
- package/payload/platform/docs/superpowers/plans/2026-07-20-task-1704-data-portal-standing-audit.md +0 -673
- package/payload/platform/docs/superpowers/plans/2026-07-20-task-1789-reseat-channel-row-fork.md +0 -1244
- package/payload/platform/docs/superpowers/plans/2026-07-20-task-1818-loop-gate-app-routes.md +0 -462
- package/payload/platform/docs/superpowers/plans/2026-07-20-task-1819-top-level-label-allowlist.md +0 -321
- package/payload/platform/docs/superpowers/plans/2026-07-20-task-1829-platform-ui-typecheck.md +0 -830
- package/payload/platform/docs/superpowers/plans/2026-07-20-task-1831-data-portal-class-derived-allowlist.md +0 -2177
- package/payload/platform/docs/superpowers/plans/2026-07-21-graph-caption-resolver.md +0 -124
- package/payload/platform/docs/superpowers/plans/2026-07-21-task-1877-bash-schema-enforcement.md +0 -107
- package/payload/platform/docs/superpowers/plans/2026-07-21-task-1887-reconcile-allowed-top-level.md +0 -205
- package/payload/platform/docs/superpowers/plans/2026-07-22-task-1899-reconcile-report-only.md +0 -748
- package/payload/platform/docs/superpowers/plans/2026-07-22-task-1910-two-way-portal-exchange.md +0 -1716
- package/payload/platform/docs/superpowers/plans/2026-07-23-task-1930-adherence-enforcement.md +0 -422
- package/payload/platform/docs/superpowers/plans/2026-07-24-task-1942-subaccount-switcher-brand-head.md +0 -327
- package/payload/platform/docs/superpowers/plans/2026-07-25-task-1974-uploads-intake-inbox.md +0 -235
- package/payload/platform/docs/superpowers/plans/2026-07-25-task-1976-intra-folder-hygiene.md +0 -215
- package/payload/platform/docs/superpowers/plans/2026-07-26-task-1902-account-owned-entry-declarations.md +0 -555
- package/payload/platform/docs/superpowers/plans/2026-07-26-task-1926-portal-push-concurrency-guard.md +0 -482
- package/payload/platform/docs/superpowers/plans/2026-07-26-task-2023-sidebar-sessions-async-reads.md +0 -394
- package/payload/platform/docs/superpowers/plans/2026-07-27-task-2016-disabled-agent-routing.md +0 -624
- package/payload/platform/docs/superpowers/plans/2026-07-27-task-2028-declared-file-write-deny.md +0 -303
- package/payload/platform/docs/superpowers/plans/2026-07-27-task-2052-account-machinery-write-fence.md +0 -250
- package/payload/platform/docs/superpowers/plans/2026-07-28-task-2097-email-signature-set.md +0 -65
- package/payload/platform/docs/superpowers/specs/2026-06-02-task-610-follower-202-retry-design.md +0 -116
- package/payload/platform/docs/superpowers/specs/2026-06-23-account-filesystem-schema-design.md +0 -170
- package/payload/platform/docs/superpowers/specs/2026-07-11-task-1557-operator-on-behalf-preference-attribution-design.md +0 -90
- package/payload/platform/docs/superpowers/specs/2026-07-13-account-schema-ontology-projection-design.md +0 -178
- package/payload/platform/docs/superpowers/specs/2026-07-14-graph-top-level-labels-ontology-single-source-design.md +0 -119
- package/payload/platform/docs/superpowers/specs/2026-07-17-task-1736-retire-mcp-stderr-tee-design.md +0 -128
- package/payload/platform/docs/superpowers/specs/2026-07-18-graph-native-ledger-design.md +0 -241
- package/payload/platform/docs/superpowers/specs/2026-07-20-task-1704-data-portal-standing-audit-design.md +0 -177
- package/payload/platform/docs/superpowers/specs/2026-07-20-task-1789-reseat-channel-row-fork-design.md +0 -201
- package/payload/platform/docs/superpowers/specs/2026-07-20-task-1818-loop-gate-app-routes-design.md +0 -217
- package/payload/platform/docs/superpowers/specs/2026-07-20-task-1819-top-level-label-allowlist-design.md +0 -80
- package/payload/platform/docs/superpowers/specs/2026-07-20-task-1820-cpu-triage-admin-tools-design.md +0 -97
- package/payload/platform/docs/superpowers/specs/2026-07-20-task-1829-platform-ui-typecheck-design.md +0 -163
- package/payload/platform/docs/superpowers/specs/2026-07-20-task-1831-data-portal-class-derived-allowlist-design.md +0 -163
- package/payload/platform/docs/superpowers/specs/2026-07-22-task-1899-reconcile-report-only-design.md +0 -121
- package/payload/platform/docs/superpowers/specs/2026-07-22-task-1910-two-way-portal-exchange-design.md +0 -103
- package/payload/platform/docs/superpowers/specs/2026-07-23-task-1930-adherence-enforcement-design.md +0 -81
- package/payload/platform/docs/superpowers/specs/2026-07-24-task-1942-subaccount-switcher-brand-head-design.md +0 -35
- package/payload/platform/docs/superpowers/specs/2026-07-26-task-1902-account-owned-entry-declarations-design.md +0 -232
- package/payload/platform/docs/superpowers/specs/2026-07-26-task-1926-portal-push-concurrency-guard-design.md +0 -200
- package/payload/platform/docs/superpowers/specs/2026-07-26-task-2014-ui-suite-nondeterminism-design.md +0 -169
- package/payload/platform/docs/superpowers/specs/2026-07-27-task-2016-disabled-agent-routing-design.md +0 -139
- package/payload/platform/docs/superpowers/specs/2026-07-27-task-2028-declared-file-write-deny-design.md +0 -127
- package/payload/platform/docs/superpowers/specs/2026-07-27-task-2052-account-machinery-write-fence-design.md +0 -150
- package/payload/platform/docs/superpowers/specs/2026-07-28-task-2097-email-signature-set-design.md +0 -155
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
# Task 1942 — Sub-account switcher to sidebar brand head — Implementation Plan
|
|
2
|
-
|
|
3
|
-
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:executing-plans. Steps use checkbox (`- [ ]`) syntax.
|
|
4
|
-
|
|
5
|
-
**Goal:** Open the sub-account picker by clicking the sidebar brand head; remove it from the footer kebab.
|
|
6
|
-
|
|
7
|
-
**Architecture:** `Sidebar.tsx` owns a `switcherOpen` state and renders the brand head as a button (icon + lockup + chevron) when the switcher is available, with `SubAccountPicker` + a full-screen scrim anchored beneath `.side-brand`. `AccountMenu.tsx` loses the switcher block, its five props, and the `SubAccountPicker` import. `globals.css` makes `.side-brand` a positioned anchor, re-anchors the panel left-aligned, and deletes the dead footer overrides.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** React 18, TypeScript, vitest + jsdom (Node 22), lucide-react icons.
|
|
10
|
-
|
|
11
|
-
## Global Constraints
|
|
12
|
-
|
|
13
|
-
- Node 22 for the jsdom test run (`platform/ui` requirement).
|
|
14
|
-
- Switcher availability gate is exactly `subAccounts.length > 1 && Boolean(onSwitchAccount)`; unchanged from today.
|
|
15
|
-
- No new task-id leaks in shipped docs; docs edit at `platform/plugins/docs/references/admin-ui.md`.
|
|
16
|
-
- All paths below are relative to the worktree's `maxy-code/platform/ui/`.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
### Task 1: Strip the switcher out of AccountMenu
|
|
21
|
-
|
|
22
|
-
**Files:**
|
|
23
|
-
- Modify: `app/components/AccountMenu.tsx`
|
|
24
|
-
- Test: `app/components/__tests__/AccountMenu.test.tsx`
|
|
25
|
-
|
|
26
|
-
**Interfaces:**
|
|
27
|
-
- Produces: `AccountMenuProps` with no `subAccounts`/`activeAccountId`/`switchingAccount`/`onSwitchAccount`/`refreshAccounts` fields.
|
|
28
|
-
|
|
29
|
-
- [ ] **Step 1: Update the test to assert the switcher is gone**
|
|
30
|
-
|
|
31
|
-
In `AccountMenu.test.tsx`, delete the two switcher tests (`renders no Switch account affordance with 0-1 sub-accounts` and `opens the sub-account picker and fires onSwitchAccount + refreshAccounts`, lines 56-88). Add one test:
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
it('renders no Switch account affordance (relocated to sidebar brand head, Task 1942)', () => {
|
|
35
|
-
render(<AccountMenu {...baseProps} variant="admin" cacheKey="k" onOpenConversations={vi.fn()} />)
|
|
36
|
-
expect(screen.queryByRole('menuitem', { name: /switch account/i })).toBeNull()
|
|
37
|
-
expect(screen.queryByPlaceholderText(/search sub-accounts/i)).toBeNull()
|
|
38
|
-
})
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Remove `subAccounts`/`activeAccountId`/`switchingAccount`/`onSwitchAccount`/`refreshAccounts` from any remaining render in the file.
|
|
42
|
-
|
|
43
|
-
- [ ] **Step 2: Run — expect fail (props still typed / item still renders)**
|
|
44
|
-
|
|
45
|
-
Run: `npx vitest run app/components/__tests__/AccountMenu.test.tsx`
|
|
46
|
-
Expected: FAIL (the Switch account menuitem still renders).
|
|
47
|
-
|
|
48
|
-
- [ ] **Step 3: Remove the switcher from AccountMenu.tsx**
|
|
49
|
-
|
|
50
|
-
- Delete the `import { SubAccountPicker } from './SubAccountPicker'` line.
|
|
51
|
-
- In `AccountMenuProps`, delete the five switcher prop declarations and their doc comment block (`subAccounts?`, `activeAccountId?`, `switchingAccount?`, `onSwitchAccount?`, `refreshAccounts?`).
|
|
52
|
-
- In the destructure, remove `subAccounts = []`, `activeAccountId = null`, `switchingAccount = false`, `onSwitchAccount`, `refreshAccounts`.
|
|
53
|
-
- Delete the `switcherOpen` state and `switcherAvailable` const.
|
|
54
|
-
- Delete the whole `{switcherAvailable && ( … <SubAccountPicker … /> … )}` JSX block.
|
|
55
|
-
- Remove `UserRound` from the lucide-react import (it was used only by the deleted block; grep the file to confirm no other use).
|
|
56
|
-
|
|
57
|
-
- [ ] **Step 4: Run — expect pass**
|
|
58
|
-
|
|
59
|
-
Run: `npx vitest run app/components/__tests__/AccountMenu.test.tsx`
|
|
60
|
-
Expected: PASS.
|
|
61
|
-
|
|
62
|
-
- [ ] **Step 5: Commit**
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
git add maxy-code/platform/ui/app/components/AccountMenu.tsx maxy-code/platform/ui/app/components/__tests__/AccountMenu.test.tsx
|
|
66
|
-
git commit -m "refactor(1942): remove sub-account switcher from AccountMenu"
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
### Task 2: Brand head becomes the switcher trigger in Sidebar
|
|
72
|
-
|
|
73
|
-
**Files:**
|
|
74
|
-
- Modify: `app/Sidebar.tsx`
|
|
75
|
-
- Test: `app/__tests__/Sidebar-subaccount-switcher.test.tsx` (create), `app/__tests__/Sidebar-user-footer.test.tsx`
|
|
76
|
-
|
|
77
|
-
**Interfaces:**
|
|
78
|
-
- Consumes: `SubAccountPicker` from `./components/SubAccountPicker`; `ChevronDown` from `lucide-react`; existing `subAccounts`/`activeAccountId`/`switchingAccount`/`onSwitchAccount`/`refreshAccounts` Sidebar props.
|
|
79
|
-
|
|
80
|
-
- [ ] **Step 1: Write the failing test (new file)**
|
|
81
|
-
|
|
82
|
-
Create `app/__tests__/Sidebar-subaccount-switcher.test.tsx`:
|
|
83
|
-
|
|
84
|
-
```tsx
|
|
85
|
-
import React from 'react'
|
|
86
|
-
import { render, screen, fireEvent } from '@testing-library/react'
|
|
87
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
88
|
-
import { Sidebar } from '../Sidebar'
|
|
89
|
-
|
|
90
|
-
function jsonResponse(body: unknown, status = 200): Response {
|
|
91
|
-
return new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } }) as Response
|
|
92
|
-
}
|
|
93
|
-
function routedFetch() {
|
|
94
|
-
return vi.spyOn(global, 'fetch').mockImplementation((input: RequestInfo | URL) => {
|
|
95
|
-
const url = typeof input === 'string' ? input : input.toString()
|
|
96
|
-
if (url.includes('/api/admin/sidebar-sessions')) return Promise.resolve(jsonResponse({ accountId: 'acct', sessions: [] }))
|
|
97
|
-
if (url.includes('/api/admin/system-stats')) return Promise.resolve(jsonResponse({ cpuPct: null, memUsedPct: 0.5, platform: 'darwin' }))
|
|
98
|
-
if (url.includes('/api/admin/version')) return Promise.resolve(jsonResponse({ installed: '1.0.0', latest: null, updateAvailable: false }))
|
|
99
|
-
return Promise.resolve(jsonResponse({}, 404))
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
const ACCOUNTS = [
|
|
103
|
-
{ accountId: 'a1', businessName: 'House', role: 'admin', isHouse: true },
|
|
104
|
-
{ accountId: 'a2', businessName: 'Client', role: 'admin', isHouse: false },
|
|
105
|
-
]
|
|
106
|
-
function baseProps(over: Record<string, unknown> = {}) {
|
|
107
|
-
return {
|
|
108
|
-
businessName: 'House', cacheKey: 'k', role: 'admin', userName: 'Ada Ops', userAvatar: null,
|
|
109
|
-
onSelectProjects: vi.fn(), onSelectTasks: vi.fn(), onCloseMobileDrawer: vi.fn(),
|
|
110
|
-
collapsed: false, mobileDrawerOpen: false, onSelectData: vi.fn(),
|
|
111
|
-
onLogout: vi.fn(), onDisconnect: vi.fn(async () => true), disconnecting: false, claudeConnected: true,
|
|
112
|
-
...over,
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
beforeEach(() => { Object.defineProperty(document, 'hidden', { value: false, configurable: true }) })
|
|
116
|
-
afterEach(() => { vi.restoreAllMocks() })
|
|
117
|
-
|
|
118
|
-
describe('Sidebar sub-account switcher on the brand head (Task 1942)', () => {
|
|
119
|
-
it('brand head is a button that toggles the picker and fires refreshAccounts', () => {
|
|
120
|
-
routedFetch()
|
|
121
|
-
const refreshAccounts = vi.fn()
|
|
122
|
-
render(<Sidebar {...baseProps({ subAccounts: ACCOUNTS, activeAccountId: 'a1', switchingAccount: false, onSwitchAccount: vi.fn(), refreshAccounts })} />)
|
|
123
|
-
const head = screen.getByRole('button', { name: /switch sub-account/i })
|
|
124
|
-
expect(screen.queryByPlaceholderText(/search sub-accounts/i)).toBeNull()
|
|
125
|
-
fireEvent.click(head)
|
|
126
|
-
expect(screen.getByPlaceholderText(/search sub-accounts/i)).toBeInTheDocument()
|
|
127
|
-
expect(refreshAccounts).toHaveBeenCalledTimes(1)
|
|
128
|
-
fireEvent.click(head)
|
|
129
|
-
expect(screen.queryByPlaceholderText(/search sub-accounts/i)).toBeNull()
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
it('selecting a card calls onSwitchAccount and closes the picker', () => {
|
|
133
|
-
routedFetch()
|
|
134
|
-
const onSwitchAccount = vi.fn()
|
|
135
|
-
render(<Sidebar {...baseProps({ subAccounts: ACCOUNTS, activeAccountId: 'a1', switchingAccount: false, onSwitchAccount, refreshAccounts: vi.fn() })} />)
|
|
136
|
-
fireEvent.click(screen.getByRole('button', { name: /switch sub-account/i }))
|
|
137
|
-
fireEvent.click(screen.getByRole('button', { name: 'Client' }))
|
|
138
|
-
expect(onSwitchAccount).toHaveBeenCalledWith('a2')
|
|
139
|
-
expect(screen.queryByPlaceholderText(/search sub-accounts/i)).toBeNull()
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('single-account install: brand head is not a switcher button and no picker mounts', () => {
|
|
143
|
-
routedFetch()
|
|
144
|
-
render(<Sidebar {...baseProps({ subAccounts: [ACCOUNTS[0]], activeAccountId: 'a1', onSwitchAccount: vi.fn() })} />)
|
|
145
|
-
expect(screen.queryByRole('button', { name: /switch sub-account/i })).toBeNull()
|
|
146
|
-
expect(screen.queryByPlaceholderText(/search sub-accounts/i)).toBeNull()
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
- [ ] **Step 2: Run — expect fail**
|
|
152
|
-
|
|
153
|
-
Run: `npx vitest run app/__tests__/Sidebar-subaccount-switcher.test.tsx`
|
|
154
|
-
Expected: FAIL (no button named "Switch sub-account").
|
|
155
|
-
|
|
156
|
-
- [ ] **Step 3: Implement the trigger in Sidebar.tsx**
|
|
157
|
-
|
|
158
|
-
Add imports: `SubAccountPicker` from `'./components/SubAccountPicker'`, and `ChevronDown` to the existing `lucide-react` import.
|
|
159
|
-
|
|
160
|
-
Add state beside `footerMenuOpen`:
|
|
161
|
-
|
|
162
|
-
```tsx
|
|
163
|
-
const [switcherOpen, setSwitcherOpen] = useState(false)
|
|
164
|
-
const switcherAvailable = (subAccounts?.length ?? 0) > 1 && Boolean(onSwitchAccount)
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
Replace the `<div className="side-brand">…</div>` block (icon + lockup) with:
|
|
168
|
-
|
|
169
|
-
```tsx
|
|
170
|
-
<div className="side-brand">
|
|
171
|
-
{switcherAvailable ? (
|
|
172
|
-
<button
|
|
173
|
-
type="button"
|
|
174
|
-
className="side-brand-trigger"
|
|
175
|
-
aria-haspopup="menu"
|
|
176
|
-
aria-expanded={switcherOpen}
|
|
177
|
-
aria-label="Switch sub-account"
|
|
178
|
-
onClick={() => {
|
|
179
|
-
const opening = !switcherOpen
|
|
180
|
-
setSwitcherOpen(opening)
|
|
181
|
-
if (opening) refreshAccounts?.()
|
|
182
|
-
console.info(`[admin-ui] op=subaccount-switcher-toggle anchor=brand-head open=${opening} available=true accounts=${subAccounts?.length ?? 0}`)
|
|
183
|
-
}}
|
|
184
|
-
>
|
|
185
|
-
<img className="side-brand-icon" src={brandIcon} alt="" aria-hidden="true" />
|
|
186
|
-
<span className="side-brand-lockup">
|
|
187
|
-
<span className="side-brand-business">{displayName}</span>
|
|
188
|
-
<span className="side-brand-product">{brand.productName}</span>
|
|
189
|
-
</span>
|
|
190
|
-
<ChevronDown size={14} className="side-brand-caret" aria-hidden="true" />
|
|
191
|
-
</button>
|
|
192
|
-
) : (
|
|
193
|
-
<>
|
|
194
|
-
<img className="side-brand-icon" src={brandIcon} alt="" aria-hidden="true" />
|
|
195
|
-
<span className="side-brand-lockup">
|
|
196
|
-
<span className="side-brand-business">{displayName}</span>
|
|
197
|
-
<span className="side-brand-product">{brand.productName}</span>
|
|
198
|
-
</span>
|
|
199
|
-
</>
|
|
200
|
-
)}
|
|
201
|
-
{switcherOpen && (
|
|
202
|
-
<>
|
|
203
|
-
<div className="side-brand-scrim" aria-hidden="true" onClick={() => setSwitcherOpen(false)} />
|
|
204
|
-
<SubAccountPicker
|
|
205
|
-
open={switcherOpen}
|
|
206
|
-
accounts={subAccounts ?? []}
|
|
207
|
-
activeAccountId={activeAccountId ?? null}
|
|
208
|
-
switching={switchingAccount ?? false}
|
|
209
|
-
onSelect={(accountId) => onSwitchAccount?.(accountId)}
|
|
210
|
-
onClose={() => setSwitcherOpen(false)}
|
|
211
|
-
/>
|
|
212
|
-
</>
|
|
213
|
-
)}
|
|
214
|
-
</div>
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
In the footer `<AccountMenu … />`, delete the five props `subAccounts`, `activeAccountId`, `switchingAccount`, `onSwitchAccount`, `refreshAccounts` (the Sidebar keeps consuming them for the head). Leave `onOpenConversations` and the rest.
|
|
218
|
-
|
|
219
|
-
- [ ] **Step 4: Run — expect pass**
|
|
220
|
-
|
|
221
|
-
Run: `npx vitest run app/__tests__/Sidebar-subaccount-switcher.test.tsx`
|
|
222
|
-
Expected: PASS.
|
|
223
|
-
|
|
224
|
-
- [ ] **Step 5: Fix the footer test that asserted the switcher was in the kebab**
|
|
225
|
-
|
|
226
|
-
In `app/__tests__/Sidebar-user-footer.test.tsx`, the test `threads the sub-account switcher and Conversations into the kebab menu` (lines 53-75) now asserts a false thing. Rewrite it to cover Conversations only:
|
|
227
|
-
|
|
228
|
-
```tsx
|
|
229
|
-
it('threads Conversations into the kebab menu (switcher moved to brand head, Task 1942)', async () => {
|
|
230
|
-
routedFetch({ cpuPct: null, memUsedPct: 0.5, platform: 'darwin' })
|
|
231
|
-
const onOpenConversations = vi.fn()
|
|
232
|
-
render(<Sidebar {...baseProps({ onOpenConversations })} />)
|
|
233
|
-
fireEvent.click(screen.getByRole('button', { name: 'Account menu' }))
|
|
234
|
-
expect(screen.queryByRole('menuitem', { name: /switch account/i })).toBeNull()
|
|
235
|
-
fireEvent.click(await screen.findByRole('menuitem', { name: /conversations/i }))
|
|
236
|
-
expect(onOpenConversations).toHaveBeenCalledTimes(1)
|
|
237
|
-
})
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
- [ ] **Step 6: Run both Sidebar suites — expect pass**
|
|
241
|
-
|
|
242
|
-
Run: `npx vitest run app/__tests__/Sidebar-subaccount-switcher.test.tsx app/__tests__/Sidebar-user-footer.test.tsx`
|
|
243
|
-
Expected: PASS.
|
|
244
|
-
|
|
245
|
-
- [ ] **Step 7: Commit**
|
|
246
|
-
|
|
247
|
-
```bash
|
|
248
|
-
git add maxy-code/platform/ui/app/Sidebar.tsx maxy-code/platform/ui/app/__tests__/Sidebar-subaccount-switcher.test.tsx maxy-code/platform/ui/app/__tests__/Sidebar-user-footer.test.tsx
|
|
249
|
-
git commit -m "feat(1942): brand head opens the sub-account picker"
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
|
|
254
|
-
### Task 3: CSS — anchor the panel under the head, style the trigger, drop dead overrides
|
|
255
|
-
|
|
256
|
-
**Files:**
|
|
257
|
-
- Modify: `app/globals.css`
|
|
258
|
-
|
|
259
|
-
**Interfaces:** consumes class names `side-brand`, `side-brand-trigger`, `side-brand-caret`, `side-brand-scrim`, `sub-account-picker-panel` from Task 2.
|
|
260
|
-
|
|
261
|
-
- [ ] **Step 1: Add `position: relative` to `.side-brand`**
|
|
262
|
-
|
|
263
|
-
In the `.side-brand { … }` rule, add `position: relative;`.
|
|
264
|
-
|
|
265
|
-
- [ ] **Step 2: Add the trigger, caret, and scrim rules** (place beside `.side-brand`)
|
|
266
|
-
|
|
267
|
-
```css
|
|
268
|
-
.side-brand-trigger {
|
|
269
|
-
display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0;
|
|
270
|
-
background: none; border: 0; padding: 0; margin: 0;
|
|
271
|
-
font: inherit; color: inherit; text-align: left; cursor: pointer;
|
|
272
|
-
}
|
|
273
|
-
.side-brand-caret { flex: none; color: var(--text-tertiary); }
|
|
274
|
-
.side-brand-trigger:hover .side-brand-caret { color: var(--text-secondary); }
|
|
275
|
-
.platform.sidebar-collapsed .side-brand-caret { display: none; }
|
|
276
|
-
.side-brand-scrim { position: fixed; inset: 0; z-index: 40; }
|
|
277
|
-
.platform.sidebar-collapsed .side-brand-scrim { display: none; }
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
- [ ] **Step 3: Re-anchor `.sub-account-picker-panel` under the head**
|
|
281
|
-
|
|
282
|
-
The brand head is now the only consumer. In `.sub-account-picker-panel`, remove `left: 50%;` and `transform: translateX(-50%);`, remove the `min-width` (if present), and set `left: 0; right: 0; margin-top: 8px; z-index: 41;` so the panel spans the head's inner width and sits above the scrim.
|
|
283
|
-
|
|
284
|
-
- [ ] **Step 4: Delete the dead footer overrides**
|
|
285
|
-
|
|
286
|
-
Delete the `.side-foot-menu .sub-account-picker-panel { … }` and `.side-foot-menu .sub-account-picker-list { … }` rules and the comment above them that describes the footer kebab anchoring.
|
|
287
|
-
|
|
288
|
-
- [ ] **Step 5: Run the class-name CSS gate + the switcher suites**
|
|
289
|
-
|
|
290
|
-
Run: `npm run -s check:classname-css 2>/dev/null || node scripts/check-classname-css.mjs`
|
|
291
|
-
Then: `npx vitest run app/__tests__/Sidebar-subaccount-switcher.test.tsx`
|
|
292
|
-
Expected: gate clean; tests PASS.
|
|
293
|
-
|
|
294
|
-
- [ ] **Step 6: Commit**
|
|
295
|
-
|
|
296
|
-
```bash
|
|
297
|
-
git add maxy-code/platform/ui/app/globals.css
|
|
298
|
-
git commit -m "style(1942): anchor sub-account picker under the sidebar brand head"
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
---
|
|
302
|
-
|
|
303
|
-
### Task 4: Docs
|
|
304
|
-
|
|
305
|
-
**Files:**
|
|
306
|
-
- Modify: `platform/plugins/docs/references/admin-ui.md`
|
|
307
|
-
|
|
308
|
-
- [ ] **Step 1: Update the switcher location**
|
|
309
|
-
|
|
310
|
-
Find the passage describing the sub-account switcher opening from the footer kebab / user-footer AccountMenu. Rewrite it to state the switcher opens by clicking the sidebar brand head (the account name), with the picker dropping beneath it; note the footer kebab no longer carries it. Keep it to the existing register; no task-id string in the shipped doc.
|
|
311
|
-
|
|
312
|
-
- [ ] **Step 2: Commit**
|
|
313
|
-
|
|
314
|
-
```bash
|
|
315
|
-
git add maxy-code/platform/plugins/docs/references/admin-ui.md
|
|
316
|
-
git commit -m "docs(1942): sub-account switcher now opens from the sidebar brand head"
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
## Self-Review
|
|
320
|
-
|
|
321
|
-
- **Spec coverage:** brand-head trigger (T2), whole-head + chevron + scrim decisions (T2/T3), AccountMenu strip (T1), CSS re-anchor + dead-override delete (T3), observability toggle log (T2 Step 3), docs (T4), test updates incl. the footer-test fix (T2 Step 5). All spec items mapped.
|
|
322
|
-
- **Placeholder scan:** none; every code step shows code.
|
|
323
|
-
- **Type consistency:** `SubAccountPicker` prop names (`open`, `accounts`, `activeAccountId`, `switching`, `onSelect`, `onClose`) match its component signature; Sidebar prop names match the existing signature.
|
|
324
|
-
|
|
325
|
-
## Known follow-ups
|
|
326
|
-
|
|
327
|
-
None at plan time. Any code-review finding out of scope is filed as a new `.tasks/` file per the sprint rules.
|
package/payload/platform/docs/superpowers/plans/2026-07-25-task-1974-uploads-intake-inbox.md
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
# Task 1974 — uploads/ intake inbox Implementation Plan
|
|
2
|
-
|
|
3
|
-
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
-
|
|
5
|
-
**Goal:** Reclassify the account `uploads/` directory from tool-owned scratch to a temporary intake inbox, and add a `stranded-intake` reconcile count so a node file-reference left pointing into `uploads/` is visible.
|
|
6
|
-
|
|
7
|
-
**Architecture:** Doctrine plus audit change, no code path change. Three prose files are edited (`SCHEMA.md`, `data-manager.md`, `internals.md`), then the `platform-architecture` SKILL.md twin is regenerated from the docs corpus so the no-drift gate passes. Detection-only, mirroring the outbound `output/` rule landed by task 1930.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** Markdown doctrine files; Node regen scripts (`docs/scripts/copy-docs.mjs`, `maxy-code/scripts/assemble-architecture-skill.mjs`); the drift gate `maxy-code/platform/scripts/check-architecture-skill-no-drift.mjs`; the bash test `fs-schema-guard.test.sh`.
|
|
10
|
-
|
|
11
|
-
## Global Constraints
|
|
12
|
-
|
|
13
|
-
- Zero em-dashes in all shipped prose.
|
|
14
|
-
- The 1930 outbound rule must survive intact: the `output/` promote-out sentence and the `scratch-refs` / `stranded` counts stay present. `stranded-intake` is appended to the output contract, never a rename of `stranded`.
|
|
15
|
-
- `uploads` stays in the `allowed-top-level` block of SCHEMA.md (files still land there).
|
|
16
|
-
- The write-path guard, the admin-UI upload handler, and `memory-ingest` `sourcePath` behaviour are unchanged.
|
|
17
|
-
- Reconcile output contract after this task: `unreachable=N broken-refs=M scratch-refs=P stranded=Q stranded-intake=R`.
|
|
18
|
-
- Paths are relative to the `maxy-code/` subtree root inside the worktree.
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
### Task 1: SCHEMA.md — reclassify uploads/ as intake inbox
|
|
23
|
-
|
|
24
|
-
**Files:**
|
|
25
|
-
- Modify: `platform/templates/account-schema/SCHEMA.md:31-39`
|
|
26
|
-
|
|
27
|
-
**Interfaces:**
|
|
28
|
-
- Produces: the doctrine text data-manager.md and internals.md refer to. No code symbols.
|
|
29
|
-
|
|
30
|
-
- [ ] **Step 1: Remove `uploads/` from the "recreated on the next write" list.**
|
|
31
|
-
|
|
32
|
-
At `SCHEMA.md:36-39`, change the list so `uploads/` is no longer among tool-owned rebuilt dirs:
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
The internal structure of these is owned by the writing tool and is recreated on
|
|
36
|
-
the next write: `url-get/`, `output/`, `generated/`, `extracted/`,
|
|
37
|
-
any published/served tree (`sites/`, `public/`), `agents/`, `specialists/`, and
|
|
38
|
-
platform-internal areas (`cache/`, `secrets/`, `state/`, `logs/`, `tmp/`).
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
- [ ] **Step 2: Add the intake-inbox rule paragraph.**
|
|
42
|
-
|
|
43
|
-
Immediately after the `output/` promote-out paragraph (ends at `SCHEMA.md:34`), insert a new paragraph. It states uploads is a temporary intake inbox, a file is promoted to its canonical bucket when its node is created, no persisted graph reference points into `uploads/`, and the per-`<attachmentId>` reason it is safe to move out of (unlike `output/`):
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
`uploads/` is a temporary intake inbox, not rebuilt scratch. A file lands at
|
|
47
|
-
`uploads/<attachmentId>/` on upload and is promoted to its canonical entity
|
|
48
|
-
bucket when its graph node is created: a Person or Organization file to
|
|
49
|
-
`contacts/<name>/`, a Project file to `projects/<name>/`, anything else to
|
|
50
|
-
`documents/`. A persisted graph reference must never point into `uploads/`.
|
|
51
|
-
Unlike `output/`, each upload writes its own `uploads/<attachmentId>/` dir and no
|
|
52
|
-
tool walks or rebuilds the subtree, so promoting a file out of it through the
|
|
53
|
-
`data-manager` specialist is safe.
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
- [ ] **Step 3: Verify the edit.**
|
|
57
|
-
|
|
58
|
-
Run:
|
|
59
|
-
```bash
|
|
60
|
-
cd platform/templates/account-schema
|
|
61
|
-
# uploads no longer in the recreated-on-next-write list
|
|
62
|
-
awk '/recreated on/,/logs.*tmp/' SCHEMA.md | grep -c 'uploads/' | grep -qx 0 && echo "OK: uploads removed from scratch list"
|
|
63
|
-
# intake-inbox rule present
|
|
64
|
-
grep -q 'temporary intake inbox' SCHEMA.md && echo "OK: intake rule present"
|
|
65
|
-
# uploads still allowed-top-level
|
|
66
|
-
grep -A40 'allowed-top-level' SCHEMA.md | grep -qx 'uploads' && echo "OK: uploads still allowed-top-level"
|
|
67
|
-
# 1930 output/ rule survives
|
|
68
|
-
grep -q 'promoted out of `output/`' SCHEMA.md && echo "OK: 1930 output rule intact"
|
|
69
|
-
# zero em-dashes in this file
|
|
70
|
-
! grep -q '—' SCHEMA.md && echo "OK: no em-dash"
|
|
71
|
-
```
|
|
72
|
-
Expected: all five OK lines.
|
|
73
|
-
|
|
74
|
-
- [ ] **Step 4: Commit.**
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
git add platform/templates/account-schema/SCHEMA.md
|
|
78
|
-
git commit -m "task: reclassify uploads/ as intake inbox in account SCHEMA.md (1974)"
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
### Task 2: data-manager.md — reconcile case (e), walk uploads/, promotion permission, output contract
|
|
84
|
-
|
|
85
|
-
**Files:**
|
|
86
|
-
- Modify: `platform/templates/specialists/agents/data-manager.md:24` (reconcile brief), `:30` (output contract), and the "What success looks like" area for the promotion permission.
|
|
87
|
-
|
|
88
|
-
**Interfaces:**
|
|
89
|
-
- Consumes: the SCHEMA.md intake-inbox rule from Task 1.
|
|
90
|
-
- Produces: the `stranded-intake=R` field that internals.md documents in Task 3.
|
|
91
|
-
|
|
92
|
-
- [ ] **Step 1: Add reconcile case (e) and include uploads/ in the walk.**
|
|
93
|
-
|
|
94
|
-
At `data-manager.md:24`, extend the counted list. After case (d), add case (e): a graph file-reference that resolves into `uploads/`, the inbound intake mirror of the `output/` scratch case. State that the walk now includes `uploads/` (a file under `uploads/` with no referencing node folds into `unreachable`). Exact appended clause inside the sentence that enumerates (a) to (d):
|
|
95
|
-
|
|
96
|
-
```
|
|
97
|
-
, and (e) graph file-references that resolve into the `uploads/` intake inbox,
|
|
98
|
-
which is a temporary landing area a file should have been promoted out of when
|
|
99
|
-
its node was created. The walk now includes `uploads/`; a file under `uploads/`
|
|
100
|
-
that no node references counts under (a) unreachable.
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
- [ ] **Step 2: Add the stewardship promotion permission for uploads/.**
|
|
104
|
-
|
|
105
|
-
In "## What success looks like" (after `data-manager.md:16`, the paired-move paragraph), add a sentence permitting promotion out of `uploads/`:
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
- A file in the `uploads/` intake inbox whose graph node exists is promoted to
|
|
109
|
-
its canonical bucket (Person or Organization to `contacts/<name>/`, Project to
|
|
110
|
-
`projects/<name>/`, else `documents/`), paired with a `database-operator`
|
|
111
|
-
`sourcePath` update in the same pass, exactly as any other move.
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
- [ ] **Step 3: Change the output contract.**
|
|
115
|
-
|
|
116
|
-
At `data-manager.md:30`, change the reconcile summary line:
|
|
117
|
-
|
|
118
|
-
```
|
|
119
|
-
For the reconcile audit: `unreachable=N broken-refs=M scratch-refs=P stranded=Q stranded-intake=R`.
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
- [ ] **Step 4: Verify the edit.**
|
|
123
|
-
|
|
124
|
-
Run:
|
|
125
|
-
```bash
|
|
126
|
-
cd platform/templates/specialists/agents
|
|
127
|
-
grep -q 'stranded-intake=R' data-manager.md && echo "OK: contract has stranded-intake"
|
|
128
|
-
grep -q 'scratch-refs=P stranded=Q' data-manager.md && echo "OK: 1930 fields survive"
|
|
129
|
-
grep -q '(e) graph file-references that resolve into the `uploads/`' data-manager.md && echo "OK: case e present"
|
|
130
|
-
grep -q 'promoted to' data-manager.md && grep -q 'sourcePath` update' data-manager.md && echo "OK: promotion permission present"
|
|
131
|
-
! grep -q '—' data-manager.md && echo "OK: no em-dash"
|
|
132
|
-
```
|
|
133
|
-
Expected: five OK lines.
|
|
134
|
-
|
|
135
|
-
- [ ] **Step 5: Commit.**
|
|
136
|
-
|
|
137
|
-
```bash
|
|
138
|
-
git add platform/templates/specialists/agents/data-manager.md
|
|
139
|
-
git commit -m "task: data-manager reconcile counts uploads/ intake drift as stranded-intake (1974)"
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
### Task 3: internals.md — document the reclassification and the stranded-intake count
|
|
145
|
-
|
|
146
|
-
**Files:**
|
|
147
|
-
- Modify: `platform/plugins/docs/references/internals.md:411`
|
|
148
|
-
|
|
149
|
-
**Interfaces:**
|
|
150
|
-
- Consumes: the reconcile contract from Task 2.
|
|
151
|
-
- Produces: the corpus text the architecture SKILL.md twin regenerates from in Task 4.
|
|
152
|
-
|
|
153
|
-
- [ ] **Step 1: Append the intake-inbox rule to the placement paragraph.**
|
|
154
|
-
|
|
155
|
-
At `internals.md:411`, the sentence currently ends: "...is counted by the `data-manager` reconcile audit (`scratch-refs`, `stranded`); making that audit run on a standing periodic cadence is a filed follow-up." Extend it with the inbound mirror. Append after the `scratch-refs`/`stranded` clause:
|
|
156
|
-
|
|
157
|
-
```
|
|
158
|
-
The inbound mirror is the `uploads/` intake inbox: an uploaded file lands at `uploads/<attachmentId>/` and is promoted to its canonical entity bucket when its graph node is created, so a persisted node reference resolving into `uploads/` is intake drift, counted by the same reconcile audit as `stranded-intake`. Unlike `output/`, `uploads/` is never rebuilt by a tool, so the `data-manager` may promote a file out of it. The reconcile output contract is `unreachable=N broken-refs=M scratch-refs=P stranded=Q stranded-intake=R`.
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
- [ ] **Step 2: Verify the edit.**
|
|
162
|
-
|
|
163
|
-
Run:
|
|
164
|
-
```bash
|
|
165
|
-
grep -q 'stranded-intake' platform/plugins/docs/references/internals.md && echo "OK: internals mentions count"
|
|
166
|
-
grep -q 'intake inbox' platform/plugins/docs/references/internals.md && echo "OK: internals mentions reclassification"
|
|
167
|
-
! grep -q '—' platform/plugins/docs/references/internals.md && echo "OK: no em-dash added"
|
|
168
|
-
```
|
|
169
|
-
Expected: three OK lines. (The last check should already pass before the edit; keep the added prose em-dash-free.)
|
|
170
|
-
|
|
171
|
-
- [ ] **Step 3: Commit.**
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
git add platform/plugins/docs/references/internals.md
|
|
175
|
-
git commit -m "task: internals.md documents uploads/ intake inbox and stranded-intake count (1974)"
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
### Task 4: Regenerate the architecture skill twin and pass the gates
|
|
181
|
-
|
|
182
|
-
**Files:**
|
|
183
|
-
- Modify (generated): `platform/plugins/admin/skills/platform-architecture/SKILL.md`
|
|
184
|
-
- Run: `docs/scripts/copy-docs.mjs`, `maxy-code/scripts/assemble-architecture-skill.mjs`, `platform/scripts/check-architecture-skill-no-drift.mjs`, `platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh`
|
|
185
|
-
|
|
186
|
-
**Interfaces:**
|
|
187
|
-
- Consumes: the edited internals.md from Task 3.
|
|
188
|
-
- Produces: a SKILL.md byte-equal to what the gate regenerates.
|
|
189
|
-
|
|
190
|
-
- [ ] **Step 1: Regenerate the corpus and the skill twin.**
|
|
191
|
-
|
|
192
|
-
Run from the worktree repo root:
|
|
193
|
-
```bash
|
|
194
|
-
node docs/scripts/copy-docs.mjs
|
|
195
|
-
node maxy-code/scripts/assemble-architecture-skill.mjs --brand maxy-code
|
|
196
|
-
```
|
|
197
|
-
Expected: `[copy-docs]` and `[platform-arch-assemble] op=write` lines, no error.
|
|
198
|
-
|
|
199
|
-
- [ ] **Step 2: Run the drift gate.**
|
|
200
|
-
|
|
201
|
-
Run:
|
|
202
|
-
```bash
|
|
203
|
-
node maxy-code/platform/scripts/check-architecture-skill-no-drift.mjs --brand maxy-code
|
|
204
|
-
```
|
|
205
|
-
Expected: exit 0, no drift reported. If it reports drift, the regen in Step 1 did not run or the SKILL.md was not re-written; re-run Step 1.
|
|
206
|
-
|
|
207
|
-
- [ ] **Step 3: Run the write-guard test (regression boundary).**
|
|
208
|
-
|
|
209
|
-
Run:
|
|
210
|
-
```bash
|
|
211
|
-
bash maxy-code/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh
|
|
212
|
-
```
|
|
213
|
-
Expected: all assertions pass. The guard is unchanged; `uploads/` is still an allowed write, so this stays green.
|
|
214
|
-
|
|
215
|
-
- [ ] **Step 4: Commit the regenerated twin (and any corpus artefact the gate expects committed).**
|
|
216
|
-
|
|
217
|
-
```bash
|
|
218
|
-
git add platform/plugins/admin/skills/platform-architecture/SKILL.md
|
|
219
|
-
git status --porcelain docs/public
|
|
220
|
-
# stage docs/public/llms-full.*.txt only if it is a tracked artefact that changed
|
|
221
|
-
git commit -m "task: regenerate platform-architecture skill twin for 1974"
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
---
|
|
225
|
-
|
|
226
|
-
## Land (Phase 6 handles this — not an implementation task)
|
|
227
|
-
|
|
228
|
-
LANES.md and task-file archival are done in Phase 6c of the sprint, not here. The task's "LANES Ready row" line describes the pre-implementation state; because this sprint implements and archives in one motion, the end state is: task file under `.tasks/archive/`, no Ready row referencing 1974, and the archive sentence naming 1974. This is a deliberate deviation from the task's literal LANES line, recorded in Plan Conformity.
|
|
229
|
-
|
|
230
|
-
## Self-Review
|
|
231
|
-
|
|
232
|
-
- **Spec coverage:** SCHEMA.md reclassification (Task 1), data-manager.md case (e) + walk + promotion + contract (Task 2), internals.md + twin regen (Tasks 3-4), LANES (Phase 6c). Every in-scope item maps to a task.
|
|
233
|
-
- **Out of scope confirmed untouched:** no auto-promotion hook, no cadence (1931), no CC-native uploads reach, no write-guard edit, no ingest-path edit.
|
|
234
|
-
- **Type consistency:** the single shared token is the output-contract string; it reads `unreachable=N broken-refs=M scratch-refs=P stranded=Q stranded-intake=R` identically in Tasks 2 and 3.
|
|
235
|
-
- **Placeholder scan:** none; every edit carries its literal text.
|