~bigbes/sr-ht-spec

394285f4cb998359c0a127454de4d32284a3ef22 — Eugene Blikh 13 days ago 90eb06e
chore(beads): file spec-rsb and spec-ovo, the two admin commands
1 files changed, 1 insertions(+), 1 deletions(-)

M .beads/issues.jsonl
M .beads/issues.jsonl => .beads/issues.jsonl +1 -1
@@ 1,6 1,6 @@
{"_type":"issue","id":"spec-zqb","title":"Phase 3: write plane — agents propose","description":"The agent half of the loop, and the service's whole premise: an agent proposes a document change, gets back a link, a human approves in a browser. Until this ships, agents can only read.","design":"Scope: proposals (branch proposals/\u003cid\u003e + Postgres row, state open-\u003emerged|rejected); the If-Match tree-splice merge with the four staleness cases and the ancestry check gitx flagged; the single agent token + mandatory provenance trailers; spec_propose / spec_comment over REST + MCP; every write response returns {proposal, url} so the agent can hand over a link. Prereqs found during Phases 1-2: (1) service.ListProposals(space, state) — graph proposal listing is stubbed and db only has ListProposalsByState; (2) IsAncestor(proposalHead, H) check before Merge so an already-merged proposal reports 'already merged' not a confusing 409; (3) auto-merge policy evaluation (.spec.yml AutoMerges) which the reconciler's 'approval=policy' inference also wants. Dispatch like Phases 1-2: proposal orchestration in service/ first and committed, then surface tools fan out. This is where the merge model and reconciler first run under real proposals rather than on paper.","status":"closed","priority":1,"issue_type":"feature","assignee":"Eugene Blikh","owner":"bigbes@gmail.com","created_at":"2026-07-23T04:08:58Z","created_by":"Eugene Blikh","updated_at":"2026-07-23T05:29:29Z","started_at":"2026-07-23T04:52:59Z","closed_at":"2026-07-23T05:29:29Z","close_reason":"Write plane shipped: service.Propose/Merge/Reject/ListProposals with provenance trailers, auto-merge policy, If-Match staleness + already-merged ancestry check; surfaces graph (Proposals port), mcpsrv spec_propose, and new api/ REST PUT — every write returns {proposal, url}. Validated end-to-end against Postgres. spec_comment deliberately deferred to Phase 5 (spec-by6), which gates the comment schema on the Phase 4 review UI; the approve/reject browser UI is Phase 4 (spec-3vz).","dependencies":[{"issue_id":"spec-zqb","depends_on_id":"spec-ejq","type":"parent-child","created_at":"2026-07-23T07:09:24Z","created_by":"Eugene Blikh","metadata":"{}"}],"dependency_count":0,"dependent_count":1,"comment_count":0}
{"_type":"issue","id":"spec-ejq","title":"spec.sr.ht — reviewable document storage for humans and agents","description":"A third custom Go service on the self-hosted SourceHut instance: agents propose documents, a human reviews and curates, agents read the approved text. One loop — bot produces, human curates, bots consume. Runs at https://spec.srht.bigb.es, deployed on phoebe as srht-spec-1. Code: git.sourcecraft.dev/bigbes/sr-ht-spec. Design: docs/DESIGN.md.","design":"DONE and deployed (Phases 0-2): core domain, gitx (bare repos + id-keyed tree-splice merge), db (Postgres schema + global ID registry), authn (unified-login cookie + agent tokens + provenance), the three receive hooks + hook RPC + daemon, service layer + reconciler, doc (warren vault/render on git objects), search (one global bleve index, per-line ru/en routing), projects (saved filter, not container), web read UI, mcpsrv read tools, graph read schema, prosediff (Phase 0 gate PASSED), specsrht space create/list, push-\u003ereindex. Live corpus: ~bigbes/rfcs holds SPEC-0001 and NOTE-0001. Verified end-to-end: validating push path, fail-closed reads, id-addressing, bilingual search, GraphQL. NOT DONE: the agent half of the loop (write plane), review UI, comments.","status":"open","priority":1,"issue_type":"epic","owner":"bigbes@gmail.com","created_at":"2026-07-23T04:08:44Z","created_by":"Eugene Blikh","updated_at":"2026-07-23T04:08:44Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"spec-ovo","title":"CLI: specsrht doc propose — open a proposal from files on the host","description":"The two agent write surfaces (REST PUT, mcpsrv spec_propose) are remote and need a bearer token. When the operator and the documents are already on the host, that token is ceremony: the process can open Postgres and the bare repos directly. Add 'specsrht doc propose ~owner/space \u003cfile\u003e...' calling service.Propose with a constructed agent principal, so the shared layer still owns If-Match, provenance, the branch cut and the auto-merge gate.","acceptance_criteria":"doc propose opens a proposal from local files and prints proposal id, branch, base and URL; --as overrides the in-space path; --proposal adds to an open proposal; --base defaults to the approved head; provenance (--agent/--session) is recorded like a remote agent's; flags parse before, after and between positionals","status":"open","priority":2,"issue_type":"feature","owner":"bigbes@gmail.com","created_at":"2026-08-05T03:23:01Z","created_by":"Eugene Blikh","updated_at":"2026-08-05T03:23:01Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"spec-ovo","title":"CLI: specsrht doc propose — open a proposal from files on the host","description":"The two agent write surfaces (REST PUT, mcpsrv spec_propose) are remote and need a bearer token. When the operator and the documents are already on the host, that token is ceremony: the process can open Postgres and the bare repos directly. Add 'specsrht doc propose ~owner/space \u003cfile\u003e...' calling service.Propose with a constructed agent principal, so the shared layer still owns If-Match, provenance, the branch cut and the auto-merge gate.","acceptance_criteria":"doc propose opens a proposal from local files and prints proposal id, branch, base and URL; --as overrides the in-space path; --proposal adds to an open proposal; --base defaults to the approved head; provenance (--agent/--session) is recorded like a remote agent's; flags parse before, after and between positionals","status":"in_progress","priority":2,"issue_type":"feature","assignee":"Eugene Blikh","owner":"bigbes@gmail.com","created_at":"2026-08-05T03:23:01Z","created_by":"Eugene Blikh","updated_at":"2026-08-05T03:23:07Z","started_at":"2026-08-05T03:23:07Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"spec-rsb","title":"CLI: specsrht token create|list|revoke","description":"db.Store has the whole agent-token lifecycle (CreateAgentToken, ListAgentTokens, RevokeAgentToken, GenerateToken/HashToken) but nothing calls it: no CLI subcommand and no web page. A freshly deployed instance therefore has no way to issue the credential the agent write plane (REST PUT and mcpsrv spec_propose) requires, short of hand-writing an INSERT with a sha256 hash. Add a 'token' admin subcommand next to 'space', in the same shape: load config, open the pool, run, exit.","acceptance_criteria":"specsrht token create \u003cname\u003e mints a token, stores only its hash, and prints the plaintext once; specsrht token list shows id/name/created/revoked; specsrht token revoke \u003cid\u003e stamps it revoked; usage errors are one clear line; unit tests cover argument parsing and row formatting","status":"in_progress","priority":2,"issue_type":"feature","assignee":"Eugene Blikh","owner":"bigbes@gmail.com","created_at":"2026-08-05T03:14:01Z","created_by":"Eugene Blikh","updated_at":"2026-08-05T03:14:05Z","started_at":"2026-08-05T03:14:05Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"spec-by6.3.5","title":"Port review UI to a line-numbered unified prose diff","description":"Replace the block-card review renderer with a real unified diff: line-numbered gutter, drag-select a line range, comment composer inline. Owner reviewed the card version against a live proposal and rejected it — labels ('ADDED PARAGRAPH') outweighed content on every row, every block carried identical chrome, and on a new file the whole page is green so the cards add noise and no signal. Split view was considered and dropped: prose lines are long and unified reads better for reflowed text. Approved prototype: https://claude.ai/code/artifact/a45e45cb-16b5-42ec-8108-84767ef9f465","design":"SELECTION IS BY LINE, ANCHORING IS BY BLOCK. Lines are what the cursor lands on; block hashes are what survive a reflow. The web layer maps a selected line range to its enclosing prosediff block and stores the existing core.CommentAnchor unchanged. service/, db/ and core/ do not move. The composer states what it will anchor to, so the indirection is visible rather than magic.\n\nTHE BLOCKING PROBLEM — word marks cannot be placed on a line for free.\nprosediff.Span is {Op, Text, Space} with no source offsets, and Tokenize\ndeliberately drops whitespace ('\\n' and ' ' both collapse to Space=true) —\nwhich is exactly what makes a rewrap invisible to the differ. So for a\nChangeModify block there is no stored answer to 'which line did this word\nchange on'.\n\nRecoverable, not free: the span script consumes the old token sequence in order\n(Equal+Delete) and the new one (Equal+Insert). Re-tokenize each source line of\nBlock.Lines, walk the script, and split a span where it crosses a line\nboundary. Needs a mapper of roughly 100 lines plus tests. Equal/Insert/Delete\nblocks need none of this — their lines map 1:1 and carry exact numbers.\n\nFALLBACK IF THE MAPPER IS NOT WANTED: render a modified block as a paired\nold/new region labelled by line RANGE rather than per line, keeping the word\nmarks. Honest and much smaller, but does not match the approved prototype.\n\nGUTTER DETAILS SETTLED IN REVIEW: one shared rail ground for both number\ntracks with a single hairline against the content (a border per cell drew a\ncage); one --row-lh shared by gutter and prose so numerals sit on the text\nbaseline rather than floating; 34px tracks; the add/delete tint starts at the\nsign column so the gutter never looks part of the change.\n\nHEADING PATH: no per-hunk breadcrumb. It restated headings visible a few rows\nabove, always so on a new file. Replaced by one sticky section readout that\nappears only once its heading has scrolled past. The path stays in the composer\nand in each thread's anchor note, where the heading is usually off screen.","acceptance_criteria":"A reviewer drags across line numbers, comments, and the thread stores an anchor identical to the one the block-card UI would have stored. Word-level marks still appear inside a modified paragraph. Unchanged lines render as context and collapse. An outdated comment still appears and is never attached to a neighbouring block.","status":"closed","priority":2,"issue_type":"feature","owner":"bigbes@gmail.com","created_at":"2026-07-25T11:40:01Z","created_by":"Eugene Blikh","updated_at":"2026-08-05T01:11:47Z","closed_at":"2026-08-05T01:11:47Z","close_reason":"Closed","dependencies":[{"issue_id":"spec-by6.3.5","depends_on_id":"spec-by6.3","type":"parent-child","created_at":"2026-07-25T14:40:01Z","created_by":"Eugene Blikh","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"spec-ejq.2","title":"CI publish task fails: build secret apk-ci-s3 is missing","description":"Every recent builds.sr.ht run fails at the publish task while every other task passes. Confirmed on jobs #244 (e97532c), #245 (2dc6b71) and #246 (c2dd1ef): 'scss keygen version build' all SUCCESS, 'publish' FAILED. Pre-existing — #244 and #245 predate the Phase 5b work, so no code change caused it. Consequence: the apk never reaches the Garage repo bucket, so apk-mirror on phoebe has nothing new to re-index and the deployed service cannot be upgraded from CI output.","design":"EVIDENCE. .build.yml declares 'secrets: [apk-ci-s3]', documented as a File secret installed at ~/.apk-ci.env carrying APK_CI_S3_ACCESS_KEY / APK_CI_S3_SECRET_KEY for the Garage repo bucket. The publish task's first real line is '. ~/.apk-ci.env'. But 'hut builds secret list' returns exactly four secrets and none is apk-ci-s3: agent1-deploy (SSH key), bencher-api-key, s3-cache-key-secret, s3-cache-key-id. So the file the task sources is never installed.\n\nNOT VERIFIED: the exact failure text. The raw log endpoint (https://builds.srht.bigb.es/query/log/246/publish/log) needs a Bearer token, and reading hut's credential file was correctly refused, so the diagnosis rests on the secret list plus the manifest rather than on the log line itself. Read the log to confirm before acting.\n\nTWO POSSIBILITIES, needs the owner to distinguish:\n1. The secret was deleted or never created — fix is to create a File secret named apk-ci-s3 at ~/.apk-ci.env (mode 600) holding the two S3 keys.\n2. builds.sr.ht resolves manifest secrets by UUID, not by name — fix is to replace the name with the secret's UUID in .build.yml.\n\nSAME BUG IN THE SIBLING: ~/data/home/sourcehut-compare/.build.yml carries a byte-identical secrets block, so compare.sr.ht's publish is broken the same way and both fix together.","acceptance_criteria":"A push to master produces a build whose publish task succeeds and uploads the .apk to the Garage repo bucket; apk-mirror on phoebe re-indexes it within 15 minutes.","notes":"RE-INDEX VERIFIED 2026-08-05, the half the close reason left open.\n\nChecked through repo.bigb.es, the public mirror apk-mirror builds from the Garage repo bucket (URL documented in the APKBUILD header; s3.bigb.es itself resolves to 192.168.88.18 and is only reachable from the LAN, which is why the first attempt to verify failed).\n\n  spec.sr.ht-0.0.78-r0.apk  200  content-length 16059260  last-modified 03:09:39 GMT\n  APKINDEX.tar.gz           200                           last-modified 03:15:00 GMT\n  index entry: P:spec.sr.ht  V:0.0.78-r0  A:x86_64  S:16059260\n\nThe size in the index matches the object byte for byte, and 0.0.78 is 'git rev-list --count cc90b4a' — the commit build #251 ran on. The index was rebuilt 5.5 minutes after the upload, inside the 15-minute window the acceptance criteria name. Both halves of the criteria are therefore met.\n\nCorrection to the close reason: the package is named spec.sr.ht-0.0.78-r0.apk, not specsrht-0.0.78-r0.apk — pkgname in APKBUILD is spec.sr.ht. The specsrht spelling 404s.","status":"closed","priority":2,"issue_type":"bug","owner":"bigbes@gmail.com","created_at":"2026-07-24T21:16:35Z","created_by":"Eugene Blikh","updated_at":"2026-08-05T03:20:11Z","closed_at":"2026-08-05T03:12:30Z","close_reason":"Owner created the File secret apk-ci-s3 (/home/build/.apk-ci.env, mode 600) on builds.srht.bigb.es; 'hut builds secret list' now shows it. Resubmit of #250 as build #251 on the same commit cc90b4a: SUCCESS, all five tasks green including publish.\n\nVERIFIED: publish runs under 'set -e' and its body is a loop of 'rclone copyto' with an echo per file, so any failed upload would have exited non-zero and failed the task. A green publish is therefore evidence the .apk reached repo/alpine/v3.22/bigbes/x86_64/ — specsrht-0.0.78-r0.apk for this commit.\n\nNOT VERIFIED from here: the apk-mirror re-index on phoebe, the second half of the acceptance criteria. s3.bigb.es is not reachable anonymously from this workstation and phoebe host access is blocked (spec-ar4). If the package turns out not to be installable, that is apk-mirror's problem rather than this repo's and wants its own bead.\n\nThe manifest needed no change: '- apk-ci-s3' resolves by name, as the diagnosis note records. The same account-level secret should also unblock sourcehut-compare, whose .build.yml carries the identical block — its next build will show it.","dependencies":[{"issue_id":"spec-ejq.2","depends_on_id":"spec-ejq","type":"parent-child","created_at":"2026-07-25T00:16:35Z","created_by":"Eugene Blikh","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}